18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for sTec s1120 PCIe SSDs. sTec was acquired in 2013 by HGST and HGST 48c2ecf20Sopenharmony_ci * was acquired by Western Digital in 2012. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2012 sTec, Inc. 78c2ecf20Sopenharmony_ci * Copyright (c) 2017 Western Digital Corporation or its affiliates. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 178c2ecf20Sopenharmony_ci#include <linux/blk-mq.h> 188c2ecf20Sopenharmony_ci#include <linux/sched.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/compiler.h> 218c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/time.h> 248c2ecf20Sopenharmony_ci#include <linux/hdreg.h> 258c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 268c2ecf20Sopenharmony_ci#include <linux/completion.h> 278c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 288c2ecf20Sopenharmony_ci#include <linux/err.h> 298c2ecf20Sopenharmony_ci#include <linux/aer.h> 308c2ecf20Sopenharmony_ci#include <linux/wait.h> 318c2ecf20Sopenharmony_ci#include <linux/stringify.h> 328c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 338c2ecf20Sopenharmony_ci#include <scsi/sg.h> 348c2ecf20Sopenharmony_ci#include <linux/io.h> 358c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 368c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "skd_s1120.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int skd_dbg_level; 418c2ecf20Sopenharmony_cistatic int skd_isr_comp_limit = 4; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define SKD_ASSERT(expr) \ 448c2ecf20Sopenharmony_ci do { \ 458c2ecf20Sopenharmony_ci if (unlikely(!(expr))) { \ 468c2ecf20Sopenharmony_ci pr_err("Assertion failed! %s,%s,%s,line=%d\n", \ 478c2ecf20Sopenharmony_ci # expr, __FILE__, __func__, __LINE__); \ 488c2ecf20Sopenharmony_ci } \ 498c2ecf20Sopenharmony_ci } while (0) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define DRV_NAME "skd" 528c2ecf20Sopenharmony_ci#define PFX DRV_NAME ": " 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STEC s1120 PCIe SSD block driver"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_STEC 0x1B39 598c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_S1120 0x0001 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define SKD_FUA_NV (1 << 1) 628c2ecf20Sopenharmony_ci#define SKD_MINORS_PER_DEVICE 16 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define SKD_MAX_QUEUE_DEPTH 200u 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define SKD_PAUSE_TIMEOUT (5 * 1000) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define SKD_N_FITMSG_BYTES (512u) 698c2ecf20Sopenharmony_ci#define SKD_MAX_REQ_PER_MSG 14 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define SKD_N_SPECIAL_FITMSG_BYTES (128u) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* SG elements are 32 bytes, so we can make this 4096 and still be under the 748c2ecf20Sopenharmony_ci * 128KB limit. That allows 4096*4K = 16M xfer size 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci#define SKD_N_SG_PER_REQ_DEFAULT 256u 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define SKD_N_COMPLETION_ENTRY 256u 798c2ecf20Sopenharmony_ci#define SKD_N_READ_CAP_BYTES (8u) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define SKD_N_INTERNAL_BYTES (512u) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define SKD_SKCOMP_SIZE \ 848c2ecf20Sopenharmony_ci ((sizeof(struct fit_completion_entry_v1) + \ 858c2ecf20Sopenharmony_ci sizeof(struct fit_comp_error_info)) * SKD_N_COMPLETION_ENTRY) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 5 bits of uniqifier, 0xF800 */ 888c2ecf20Sopenharmony_ci#define SKD_ID_TABLE_MASK (3u << 8u) 898c2ecf20Sopenharmony_ci#define SKD_ID_RW_REQUEST (0u << 8u) 908c2ecf20Sopenharmony_ci#define SKD_ID_INTERNAL (1u << 8u) 918c2ecf20Sopenharmony_ci#define SKD_ID_FIT_MSG (3u << 8u) 928c2ecf20Sopenharmony_ci#define SKD_ID_SLOT_MASK 0x00FFu 938c2ecf20Sopenharmony_ci#define SKD_ID_SLOT_AND_TABLE_MASK 0x03FFu 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define SKD_N_MAX_SECTORS 2048u 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#define SKD_MAX_RETRIES 2u 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define SKD_TIMER_SECONDS(seconds) (seconds) 1008c2ecf20Sopenharmony_ci#define SKD_TIMER_MINUTES(minutes) ((minutes) * (60)) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define INQ_STD_NBYTES 36 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cienum skd_drvr_state { 1058c2ecf20Sopenharmony_ci SKD_DRVR_STATE_LOAD, 1068c2ecf20Sopenharmony_ci SKD_DRVR_STATE_IDLE, 1078c2ecf20Sopenharmony_ci SKD_DRVR_STATE_BUSY, 1088c2ecf20Sopenharmony_ci SKD_DRVR_STATE_STARTING, 1098c2ecf20Sopenharmony_ci SKD_DRVR_STATE_ONLINE, 1108c2ecf20Sopenharmony_ci SKD_DRVR_STATE_PAUSING, 1118c2ecf20Sopenharmony_ci SKD_DRVR_STATE_PAUSED, 1128c2ecf20Sopenharmony_ci SKD_DRVR_STATE_RESTARTING, 1138c2ecf20Sopenharmony_ci SKD_DRVR_STATE_RESUMING, 1148c2ecf20Sopenharmony_ci SKD_DRVR_STATE_STOPPING, 1158c2ecf20Sopenharmony_ci SKD_DRVR_STATE_FAULT, 1168c2ecf20Sopenharmony_ci SKD_DRVR_STATE_DISAPPEARED, 1178c2ecf20Sopenharmony_ci SKD_DRVR_STATE_PROTOCOL_MISMATCH, 1188c2ecf20Sopenharmony_ci SKD_DRVR_STATE_BUSY_ERASE, 1198c2ecf20Sopenharmony_ci SKD_DRVR_STATE_BUSY_SANITIZE, 1208c2ecf20Sopenharmony_ci SKD_DRVR_STATE_BUSY_IMMINENT, 1218c2ecf20Sopenharmony_ci SKD_DRVR_STATE_WAIT_BOOT, 1228c2ecf20Sopenharmony_ci SKD_DRVR_STATE_SYNCING, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define SKD_WAIT_BOOT_TIMO SKD_TIMER_SECONDS(90u) 1268c2ecf20Sopenharmony_ci#define SKD_STARTING_TIMO SKD_TIMER_SECONDS(8u) 1278c2ecf20Sopenharmony_ci#define SKD_RESTARTING_TIMO SKD_TIMER_MINUTES(4u) 1288c2ecf20Sopenharmony_ci#define SKD_BUSY_TIMO SKD_TIMER_MINUTES(20u) 1298c2ecf20Sopenharmony_ci#define SKD_STARTED_BUSY_TIMO SKD_TIMER_SECONDS(60u) 1308c2ecf20Sopenharmony_ci#define SKD_START_WAIT_SECONDS 90u 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cienum skd_req_state { 1338c2ecf20Sopenharmony_ci SKD_REQ_STATE_IDLE, 1348c2ecf20Sopenharmony_ci SKD_REQ_STATE_SETUP, 1358c2ecf20Sopenharmony_ci SKD_REQ_STATE_BUSY, 1368c2ecf20Sopenharmony_ci SKD_REQ_STATE_COMPLETED, 1378c2ecf20Sopenharmony_ci SKD_REQ_STATE_TIMEOUT, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cienum skd_check_status_action { 1418c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_GOOD, 1428c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_SMART_ALERT, 1438c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REQUEUE_REQUEST, 1448c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_ERROR, 1458c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_BUSY_IMMINENT, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistruct skd_msg_buf { 1498c2ecf20Sopenharmony_ci struct fit_msg_hdr fmh; 1508c2ecf20Sopenharmony_ci struct skd_scsi_request scsi[SKD_MAX_REQ_PER_MSG]; 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistruct skd_fitmsg_context { 1548c2ecf20Sopenharmony_ci u32 id; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci u32 length; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci struct skd_msg_buf *msg_buf; 1598c2ecf20Sopenharmony_ci dma_addr_t mb_dma_address; 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistruct skd_request_context { 1638c2ecf20Sopenharmony_ci enum skd_req_state state; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci u16 id; 1668c2ecf20Sopenharmony_ci u32 fitmsg_id; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci u8 flush_cmd; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci enum dma_data_direction data_dir; 1718c2ecf20Sopenharmony_ci struct scatterlist *sg; 1728c2ecf20Sopenharmony_ci u32 n_sg; 1738c2ecf20Sopenharmony_ci u32 sg_byte_count; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sksg_list; 1768c2ecf20Sopenharmony_ci dma_addr_t sksg_dma_address; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 completion; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci struct fit_comp_error_info err_info; 1818c2ecf20Sopenharmony_ci int retries; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci blk_status_t status; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct skd_special_context { 1878c2ecf20Sopenharmony_ci struct skd_request_context req; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci void *data_buf; 1908c2ecf20Sopenharmony_ci dma_addr_t db_dma_address; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci struct skd_msg_buf *msg_buf; 1938c2ecf20Sopenharmony_ci dma_addr_t mb_dma_address; 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_citypedef enum skd_irq_type { 1978c2ecf20Sopenharmony_ci SKD_IRQ_LEGACY, 1988c2ecf20Sopenharmony_ci SKD_IRQ_MSI, 1998c2ecf20Sopenharmony_ci SKD_IRQ_MSIX 2008c2ecf20Sopenharmony_ci} skd_irq_type_t; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#define SKD_MAX_BARS 2 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistruct skd_device { 2058c2ecf20Sopenharmony_ci void __iomem *mem_map[SKD_MAX_BARS]; 2068c2ecf20Sopenharmony_ci resource_size_t mem_phys[SKD_MAX_BARS]; 2078c2ecf20Sopenharmony_ci u32 mem_size[SKD_MAX_BARS]; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci struct skd_msix_entry *msix_entries; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci struct pci_dev *pdev; 2128c2ecf20Sopenharmony_ci int pcie_error_reporting_is_enabled; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci spinlock_t lock; 2158c2ecf20Sopenharmony_ci struct gendisk *disk; 2168c2ecf20Sopenharmony_ci struct blk_mq_tag_set tag_set; 2178c2ecf20Sopenharmony_ci struct request_queue *queue; 2188c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg; 2198c2ecf20Sopenharmony_ci struct device *class_dev; 2208c2ecf20Sopenharmony_ci int gendisk_on; 2218c2ecf20Sopenharmony_ci int sync_done; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci u32 devno; 2248c2ecf20Sopenharmony_ci u32 major; 2258c2ecf20Sopenharmony_ci char isr_name[30]; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci enum skd_drvr_state state; 2288c2ecf20Sopenharmony_ci u32 drive_state; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci u32 cur_max_queue_depth; 2318c2ecf20Sopenharmony_ci u32 queue_low_water_mark; 2328c2ecf20Sopenharmony_ci u32 dev_max_queue_depth; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci u32 num_fitmsg_context; 2358c2ecf20Sopenharmony_ci u32 num_req_context; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg_table; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci struct skd_special_context internal_skspcl; 2408c2ecf20Sopenharmony_ci u32 read_cap_blocksize; 2418c2ecf20Sopenharmony_ci u32 read_cap_last_lba; 2428c2ecf20Sopenharmony_ci int read_cap_is_valid; 2438c2ecf20Sopenharmony_ci int inquiry_is_valid; 2448c2ecf20Sopenharmony_ci u8 inq_serial_num[13]; /*12 chars plus null term */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci u8 skcomp_cycle; 2478c2ecf20Sopenharmony_ci u32 skcomp_ix; 2488c2ecf20Sopenharmony_ci struct kmem_cache *msgbuf_cache; 2498c2ecf20Sopenharmony_ci struct kmem_cache *sglist_cache; 2508c2ecf20Sopenharmony_ci struct kmem_cache *databuf_cache; 2518c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcomp_table; 2528c2ecf20Sopenharmony_ci struct fit_comp_error_info *skerr_table; 2538c2ecf20Sopenharmony_ci dma_addr_t cq_dma_address; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci wait_queue_head_t waitq; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci struct timer_list timer; 2588c2ecf20Sopenharmony_ci u32 timer_countdown; 2598c2ecf20Sopenharmony_ci u32 timer_substate; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci int sgs_per_request; 2628c2ecf20Sopenharmony_ci u32 last_mtd; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci u32 proto_ver; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci int dbg_level; 2678c2ecf20Sopenharmony_ci u32 connect_time_stamp; 2688c2ecf20Sopenharmony_ci int connect_retries; 2698c2ecf20Sopenharmony_ci#define SKD_MAX_CONNECT_RETRIES 16 2708c2ecf20Sopenharmony_ci u32 drive_jiffies; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci u32 timo_slot; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci struct work_struct start_queue; 2758c2ecf20Sopenharmony_ci struct work_struct completion_worker; 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci#define SKD_WRITEL(DEV, VAL, OFF) skd_reg_write32(DEV, VAL, OFF) 2798c2ecf20Sopenharmony_ci#define SKD_READL(DEV, OFF) skd_reg_read32(DEV, OFF) 2808c2ecf20Sopenharmony_ci#define SKD_WRITEQ(DEV, VAL, OFF) skd_reg_write64(DEV, VAL, OFF) 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic inline u32 skd_reg_read32(struct skd_device *skdev, u32 offset) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u32 val = readl(skdev->mem_map[1] + offset); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level >= 2)) 2878c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "offset %x = %x\n", offset, val); 2888c2ecf20Sopenharmony_ci return val; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic inline void skd_reg_write32(struct skd_device *skdev, u32 val, 2928c2ecf20Sopenharmony_ci u32 offset) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci writel(val, skdev->mem_map[1] + offset); 2958c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level >= 2)) 2968c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "offset %x = %x\n", offset, val); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic inline void skd_reg_write64(struct skd_device *skdev, u64 val, 3008c2ecf20Sopenharmony_ci u32 offset) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci writeq(val, skdev->mem_map[1] + offset); 3038c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level >= 2)) 3048c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "offset %x = %016llx\n", offset, 3058c2ecf20Sopenharmony_ci val); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define SKD_IRQ_DEFAULT SKD_IRQ_MSIX 3108c2ecf20Sopenharmony_cistatic int skd_isr_type = SKD_IRQ_DEFAULT; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cimodule_param(skd_isr_type, int, 0444); 3138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_isr_type, "Interrupt type capability." 3148c2ecf20Sopenharmony_ci " (0==legacy, 1==MSI, 2==MSI-X, default==1)"); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci#define SKD_MAX_REQ_PER_MSG_DEFAULT 1 3178c2ecf20Sopenharmony_cistatic int skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cimodule_param(skd_max_req_per_msg, int, 0444); 3208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_max_req_per_msg, 3218c2ecf20Sopenharmony_ci "Maximum SCSI requests packed in a single message." 3228c2ecf20Sopenharmony_ci " (1-" __stringify(SKD_MAX_REQ_PER_MSG) ", default==1)"); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci#define SKD_MAX_QUEUE_DEPTH_DEFAULT 64 3258c2ecf20Sopenharmony_ci#define SKD_MAX_QUEUE_DEPTH_DEFAULT_STR "64" 3268c2ecf20Sopenharmony_cistatic int skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cimodule_param(skd_max_queue_depth, int, 0444); 3298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_max_queue_depth, 3308c2ecf20Sopenharmony_ci "Maximum SCSI requests issued to s1120." 3318c2ecf20Sopenharmony_ci " (1-200, default==" SKD_MAX_QUEUE_DEPTH_DEFAULT_STR ")"); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; 3348c2ecf20Sopenharmony_cimodule_param(skd_sgs_per_request, int, 0444); 3358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_sgs_per_request, 3368c2ecf20Sopenharmony_ci "Maximum SG elements per block request." 3378c2ecf20Sopenharmony_ci " (1-4096, default==256)"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int skd_max_pass_thru = 1; 3408c2ecf20Sopenharmony_cimodule_param(skd_max_pass_thru, int, 0444); 3418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_max_pass_thru, 3428c2ecf20Sopenharmony_ci "Maximum SCSI pass-thru at a time. IGNORED"); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cimodule_param(skd_dbg_level, int, 0444); 3458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_dbg_level, "s1120 debug level (0,1,2)"); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cimodule_param(skd_isr_comp_limit, int, 0444); 3488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(skd_isr_comp_limit, "s1120 isr comp limit (0=none) default=4"); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* Major device number dynamically assigned. */ 3518c2ecf20Sopenharmony_cistatic u32 skd_major; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic void skd_destruct(struct skd_device *skdev); 3548c2ecf20Sopenharmony_cistatic const struct block_device_operations skd_blockdev_ops; 3558c2ecf20Sopenharmony_cistatic void skd_send_fitmsg(struct skd_device *skdev, 3568c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg); 3578c2ecf20Sopenharmony_cistatic void skd_send_special_fitmsg(struct skd_device *skdev, 3588c2ecf20Sopenharmony_ci struct skd_special_context *skspcl); 3598c2ecf20Sopenharmony_cistatic bool skd_preop_sg_list(struct skd_device *skdev, 3608c2ecf20Sopenharmony_ci struct skd_request_context *skreq); 3618c2ecf20Sopenharmony_cistatic void skd_postop_sg_list(struct skd_device *skdev, 3628c2ecf20Sopenharmony_ci struct skd_request_context *skreq); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic void skd_restart_device(struct skd_device *skdev); 3658c2ecf20Sopenharmony_cistatic int skd_quiesce_dev(struct skd_device *skdev); 3668c2ecf20Sopenharmony_cistatic int skd_unquiesce_dev(struct skd_device *skdev); 3678c2ecf20Sopenharmony_cistatic void skd_disable_interrupts(struct skd_device *skdev); 3688c2ecf20Sopenharmony_cistatic void skd_isr_fwstate(struct skd_device *skdev); 3698c2ecf20Sopenharmony_cistatic void skd_recover_requests(struct skd_device *skdev); 3708c2ecf20Sopenharmony_cistatic void skd_soft_reset(struct skd_device *skdev); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ciconst char *skd_drive_state_to_str(int state); 3738c2ecf20Sopenharmony_ciconst char *skd_skdev_state_to_str(enum skd_drvr_state state); 3748c2ecf20Sopenharmony_cistatic void skd_log_skdev(struct skd_device *skdev, const char *event); 3758c2ecf20Sopenharmony_cistatic void skd_log_skreq(struct skd_device *skdev, 3768c2ecf20Sopenharmony_ci struct skd_request_context *skreq, const char *event); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/* 3798c2ecf20Sopenharmony_ci ***************************************************************************** 3808c2ecf20Sopenharmony_ci * READ/WRITE REQUESTS 3818c2ecf20Sopenharmony_ci ***************************************************************************** 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_cistatic bool skd_inc_in_flight(struct request *rq, void *data, bool reserved) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci int *count = data; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci count++; 3888c2ecf20Sopenharmony_ci return true; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int skd_in_flight(struct skd_device *skdev) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int count = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci blk_mq_tagset_busy_iter(&skdev->tag_set, skd_inc_in_flight, &count); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return count; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void 4018c2ecf20Sopenharmony_ciskd_prep_rw_cdb(struct skd_scsi_request *scsi_req, 4028c2ecf20Sopenharmony_ci int data_dir, unsigned lba, 4038c2ecf20Sopenharmony_ci unsigned count) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci if (data_dir == READ) 4068c2ecf20Sopenharmony_ci scsi_req->cdb[0] = READ_10; 4078c2ecf20Sopenharmony_ci else 4088c2ecf20Sopenharmony_ci scsi_req->cdb[0] = WRITE_10; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci scsi_req->cdb[1] = 0; 4118c2ecf20Sopenharmony_ci scsi_req->cdb[2] = (lba & 0xff000000) >> 24; 4128c2ecf20Sopenharmony_ci scsi_req->cdb[3] = (lba & 0xff0000) >> 16; 4138c2ecf20Sopenharmony_ci scsi_req->cdb[4] = (lba & 0xff00) >> 8; 4148c2ecf20Sopenharmony_ci scsi_req->cdb[5] = (lba & 0xff); 4158c2ecf20Sopenharmony_ci scsi_req->cdb[6] = 0; 4168c2ecf20Sopenharmony_ci scsi_req->cdb[7] = (count & 0xff00) >> 8; 4178c2ecf20Sopenharmony_ci scsi_req->cdb[8] = count & 0xff; 4188c2ecf20Sopenharmony_ci scsi_req->cdb[9] = 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void 4228c2ecf20Sopenharmony_ciskd_prep_zerosize_flush_cdb(struct skd_scsi_request *scsi_req, 4238c2ecf20Sopenharmony_ci struct skd_request_context *skreq) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci skreq->flush_cmd = 1; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci scsi_req->cdb[0] = SYNCHRONIZE_CACHE; 4288c2ecf20Sopenharmony_ci scsi_req->cdb[1] = 0; 4298c2ecf20Sopenharmony_ci scsi_req->cdb[2] = 0; 4308c2ecf20Sopenharmony_ci scsi_req->cdb[3] = 0; 4318c2ecf20Sopenharmony_ci scsi_req->cdb[4] = 0; 4328c2ecf20Sopenharmony_ci scsi_req->cdb[5] = 0; 4338c2ecf20Sopenharmony_ci scsi_req->cdb[6] = 0; 4348c2ecf20Sopenharmony_ci scsi_req->cdb[7] = 0; 4358c2ecf20Sopenharmony_ci scsi_req->cdb[8] = 0; 4368c2ecf20Sopenharmony_ci scsi_req->cdb[9] = 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * Return true if and only if all pending requests should be failed. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_cistatic bool skd_fail_all(struct request_queue *q) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct skd_device *skdev = q->queuedata; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci SKD_ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci skd_log_skdev(skdev, "req_not_online"); 4498c2ecf20Sopenharmony_ci switch (skdev->state) { 4508c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSING: 4518c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSED: 4528c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 4538c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 4548c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_WAIT_BOOT: 4558c2ecf20Sopenharmony_ci /* In case of starting, we haven't started the queue, 4568c2ecf20Sopenharmony_ci * so we can't get here... but requests are 4578c2ecf20Sopenharmony_ci * possibly hanging out waiting for us because we 4588c2ecf20Sopenharmony_ci * reported the dev/skd0 already. They'll wait 4598c2ecf20Sopenharmony_ci * forever if connect doesn't complete. 4608c2ecf20Sopenharmony_ci * What to do??? delay dev/skd0 ?? 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY: 4638c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_IMMINENT: 4648c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_ERASE: 4658c2ecf20Sopenharmony_ci return false; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_SANITIZE: 4688c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STOPPING: 4698c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_SYNCING: 4708c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_FAULT: 4718c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_DISAPPEARED: 4728c2ecf20Sopenharmony_ci default: 4738c2ecf20Sopenharmony_ci return true; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic blk_status_t skd_mq_queue_rq(struct blk_mq_hw_ctx *hctx, 4788c2ecf20Sopenharmony_ci const struct blk_mq_queue_data *mqd) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct request *const req = mqd->rq; 4818c2ecf20Sopenharmony_ci struct request_queue *const q = req->q; 4828c2ecf20Sopenharmony_ci struct skd_device *skdev = q->queuedata; 4838c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg; 4848c2ecf20Sopenharmony_ci struct fit_msg_hdr *fmh; 4858c2ecf20Sopenharmony_ci const u32 tag = blk_mq_unique_tag(req); 4868c2ecf20Sopenharmony_ci struct skd_request_context *const skreq = blk_mq_rq_to_pdu(req); 4878c2ecf20Sopenharmony_ci struct skd_scsi_request *scsi_req; 4888c2ecf20Sopenharmony_ci unsigned long flags = 0; 4898c2ecf20Sopenharmony_ci const u32 lba = blk_rq_pos(req); 4908c2ecf20Sopenharmony_ci const u32 count = blk_rq_sectors(req); 4918c2ecf20Sopenharmony_ci const int data_dir = rq_data_dir(req); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (unlikely(skdev->state != SKD_DRVR_STATE_ONLINE)) 4948c2ecf20Sopenharmony_ci return skd_fail_all(q) ? BLK_STS_IOERR : BLK_STS_RESOURCE; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!(req->rq_flags & RQF_DONTPREP)) { 4978c2ecf20Sopenharmony_ci skreq->retries = 0; 4988c2ecf20Sopenharmony_ci req->rq_flags |= RQF_DONTPREP; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci blk_mq_start_request(req); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci WARN_ONCE(tag >= skd_max_queue_depth, "%#x > %#x (nr_requests = %lu)\n", 5048c2ecf20Sopenharmony_ci tag, skd_max_queue_depth, q->nr_requests); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci SKD_ASSERT(skreq->state == SKD_REQ_STATE_IDLE); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 5098c2ecf20Sopenharmony_ci "new req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", req, lba, 5108c2ecf20Sopenharmony_ci lba, count, count, data_dir); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci skreq->id = tag + SKD_ID_RW_REQUEST; 5138c2ecf20Sopenharmony_ci skreq->flush_cmd = 0; 5148c2ecf20Sopenharmony_ci skreq->n_sg = 0; 5158c2ecf20Sopenharmony_ci skreq->sg_byte_count = 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci skreq->fitmsg_id = 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci skreq->data_dir = data_dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (req->bio && !skd_preop_sg_list(skdev, skreq)) { 5228c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "error Out\n"); 5238c2ecf20Sopenharmony_ci skreq->status = BLK_STS_RESOURCE; 5248c2ecf20Sopenharmony_ci blk_mq_complete_request(req); 5258c2ecf20Sopenharmony_ci return BLK_STS_OK; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci dma_sync_single_for_device(&skdev->pdev->dev, skreq->sksg_dma_address, 5298c2ecf20Sopenharmony_ci skreq->n_sg * 5308c2ecf20Sopenharmony_ci sizeof(struct fit_sg_descriptor), 5318c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* Either a FIT msg is in progress or we have to start one. */ 5348c2ecf20Sopenharmony_ci if (skd_max_req_per_msg == 1) { 5358c2ecf20Sopenharmony_ci skmsg = NULL; 5368c2ecf20Sopenharmony_ci } else { 5378c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 5388c2ecf20Sopenharmony_ci skmsg = skdev->skmsg; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci if (!skmsg) { 5418c2ecf20Sopenharmony_ci skmsg = &skdev->skmsg_table[tag]; 5428c2ecf20Sopenharmony_ci skdev->skmsg = skmsg; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Initialize the FIT msg header */ 5458c2ecf20Sopenharmony_ci fmh = &skmsg->msg_buf->fmh; 5468c2ecf20Sopenharmony_ci memset(fmh, 0, sizeof(*fmh)); 5478c2ecf20Sopenharmony_ci fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; 5488c2ecf20Sopenharmony_ci skmsg->length = sizeof(*fmh); 5498c2ecf20Sopenharmony_ci } else { 5508c2ecf20Sopenharmony_ci fmh = &skmsg->msg_buf->fmh; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci skreq->fitmsg_id = skmsg->id; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci scsi_req = &skmsg->msg_buf->scsi[fmh->num_protocol_cmds_coalesced]; 5568c2ecf20Sopenharmony_ci memset(scsi_req, 0, sizeof(*scsi_req)); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci scsi_req->hdr.tag = skreq->id; 5598c2ecf20Sopenharmony_ci scsi_req->hdr.sg_list_dma_address = 5608c2ecf20Sopenharmony_ci cpu_to_be64(skreq->sksg_dma_address); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (req_op(req) == REQ_OP_FLUSH) { 5638c2ecf20Sopenharmony_ci skd_prep_zerosize_flush_cdb(scsi_req, skreq); 5648c2ecf20Sopenharmony_ci SKD_ASSERT(skreq->flush_cmd == 1); 5658c2ecf20Sopenharmony_ci } else { 5668c2ecf20Sopenharmony_ci skd_prep_rw_cdb(scsi_req, data_dir, lba, count); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (req->cmd_flags & REQ_FUA) 5708c2ecf20Sopenharmony_ci scsi_req->cdb[1] |= SKD_FUA_NV; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci scsi_req->hdr.sg_list_len_bytes = cpu_to_be32(skreq->sg_byte_count); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Complete resource allocations. */ 5758c2ecf20Sopenharmony_ci skreq->state = SKD_REQ_STATE_BUSY; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci skmsg->length += sizeof(struct skd_scsi_request); 5788c2ecf20Sopenharmony_ci fmh->num_protocol_cmds_coalesced++; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "req=0x%x busy=%d\n", skreq->id, 5818c2ecf20Sopenharmony_ci skd_in_flight(skdev)); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* 5848c2ecf20Sopenharmony_ci * If the FIT msg buffer is full send it. 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ci if (skd_max_req_per_msg == 1) { 5878c2ecf20Sopenharmony_ci skd_send_fitmsg(skdev, skmsg); 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci if (mqd->last || 5908c2ecf20Sopenharmony_ci fmh->num_protocol_cmds_coalesced >= skd_max_req_per_msg) { 5918c2ecf20Sopenharmony_ci skd_send_fitmsg(skdev, skmsg); 5928c2ecf20Sopenharmony_ci skdev->skmsg = NULL; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return BLK_STS_OK; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return skd_timed_out(struct request *req, 6018c2ecf20Sopenharmony_ci bool reserved) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct skd_device *skdev = req->q->queuedata; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "request with tag %#x timed out\n", 6068c2ecf20Sopenharmony_ci blk_mq_unique_tag(req)); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return BLK_EH_RESET_TIMER; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic void skd_complete_rq(struct request *req) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct skd_request_context *skreq = blk_mq_rq_to_pdu(req); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci blk_mq_end_request(req, skreq->status); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic bool skd_preop_sg_list(struct skd_device *skdev, 6198c2ecf20Sopenharmony_ci struct skd_request_context *skreq) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct request *req = blk_mq_rq_from_pdu(skreq); 6228c2ecf20Sopenharmony_ci struct scatterlist *sgl = &skreq->sg[0], *sg; 6238c2ecf20Sopenharmony_ci int n_sg; 6248c2ecf20Sopenharmony_ci int i; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci skreq->sg_byte_count = 0; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci WARN_ON_ONCE(skreq->data_dir != DMA_TO_DEVICE && 6298c2ecf20Sopenharmony_ci skreq->data_dir != DMA_FROM_DEVICE); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci n_sg = blk_rq_map_sg(skdev->queue, req, sgl); 6328c2ecf20Sopenharmony_ci if (n_sg <= 0) 6338c2ecf20Sopenharmony_ci return false; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* 6368c2ecf20Sopenharmony_ci * Map scatterlist to PCI bus addresses. 6378c2ecf20Sopenharmony_ci * Note PCI might change the number of entries. 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci n_sg = dma_map_sg(&skdev->pdev->dev, sgl, n_sg, skreq->data_dir); 6408c2ecf20Sopenharmony_ci if (n_sg <= 0) 6418c2ecf20Sopenharmony_ci return false; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci SKD_ASSERT(n_sg <= skdev->sgs_per_request); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci skreq->n_sg = n_sg; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, n_sg, i) { 6488c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; 6498c2ecf20Sopenharmony_ci u32 cnt = sg_dma_len(sg); 6508c2ecf20Sopenharmony_ci uint64_t dma_addr = sg_dma_address(sg); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci sgd->control = FIT_SGD_CONTROL_NOT_LAST; 6538c2ecf20Sopenharmony_ci sgd->byte_count = cnt; 6548c2ecf20Sopenharmony_ci skreq->sg_byte_count += cnt; 6558c2ecf20Sopenharmony_ci sgd->host_side_addr = dma_addr; 6568c2ecf20Sopenharmony_ci sgd->dev_side_addr = 0; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL; 6608c2ecf20Sopenharmony_ci skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level > 1)) { 6638c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 6648c2ecf20Sopenharmony_ci "skreq=%x sksg_list=%p sksg_dma=%pad\n", 6658c2ecf20Sopenharmony_ci skreq->id, skreq->sksg_list, &skreq->sksg_dma_address); 6668c2ecf20Sopenharmony_ci for (i = 0; i < n_sg; i++) { 6678c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 6708c2ecf20Sopenharmony_ci " sg[%d] count=%u ctrl=0x%x addr=0x%llx next=0x%llx\n", 6718c2ecf20Sopenharmony_ci i, sgd->byte_count, sgd->control, 6728c2ecf20Sopenharmony_ci sgd->host_side_addr, sgd->next_desc_ptr); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return true; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic void skd_postop_sg_list(struct skd_device *skdev, 6808c2ecf20Sopenharmony_ci struct skd_request_context *skreq) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci /* 6838c2ecf20Sopenharmony_ci * restore the next ptr for next IO request so we 6848c2ecf20Sopenharmony_ci * don't have to set it every time. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = 6878c2ecf20Sopenharmony_ci skreq->sksg_dma_address + 6888c2ecf20Sopenharmony_ci ((skreq->n_sg) * sizeof(struct fit_sg_descriptor)); 6898c2ecf20Sopenharmony_ci dma_unmap_sg(&skdev->pdev->dev, &skreq->sg[0], skreq->n_sg, 6908c2ecf20Sopenharmony_ci skreq->data_dir); 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/* 6948c2ecf20Sopenharmony_ci ***************************************************************************** 6958c2ecf20Sopenharmony_ci * TIMER 6968c2ecf20Sopenharmony_ci ***************************************************************************** 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void skd_timer_tick_not_online(struct skd_device *skdev); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic void skd_start_queue(struct work_struct *work) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct skd_device *skdev = container_of(work, typeof(*skdev), 7048c2ecf20Sopenharmony_ci start_queue); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * Although it is safe to call blk_start_queue() from interrupt 7088c2ecf20Sopenharmony_ci * context, blk_mq_start_hw_queues() must not be called from 7098c2ecf20Sopenharmony_ci * interrupt context. 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_ci blk_mq_start_hw_queues(skdev->queue); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void skd_timer_tick(struct timer_list *t) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct skd_device *skdev = from_timer(skdev, t, timer); 7178c2ecf20Sopenharmony_ci unsigned long reqflags; 7188c2ecf20Sopenharmony_ci u32 state; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_FAULT) 7218c2ecf20Sopenharmony_ci /* The driver has declared fault, and we want it to 7228c2ecf20Sopenharmony_ci * stay that way until driver is reloaded. 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_ci return; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, reqflags); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_STATUS); 7298c2ecf20Sopenharmony_ci state &= FIT_SR_DRIVE_STATE_MASK; 7308c2ecf20Sopenharmony_ci if (state != skdev->drive_state) 7318c2ecf20Sopenharmony_ci skd_isr_fwstate(skdev); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (skdev->state != SKD_DRVR_STATE_ONLINE) 7348c2ecf20Sopenharmony_ci skd_timer_tick_not_online(skdev); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci mod_timer(&skdev->timer, (jiffies + HZ)); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, reqflags); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void skd_timer_tick_not_online(struct skd_device *skdev) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci switch (skdev->state) { 7448c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_IDLE: 7458c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_LOAD: 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_SANITIZE: 7488c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 7498c2ecf20Sopenharmony_ci "drive busy sanitize[%x], driver[%x]\n", 7508c2ecf20Sopenharmony_ci skdev->drive_state, skdev->state); 7518c2ecf20Sopenharmony_ci /* If we've been in sanitize for 3 seconds, we figure we're not 7528c2ecf20Sopenharmony_ci * going to get anymore completions, so recover requests now 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_ci if (skdev->timer_countdown > 0) { 7558c2ecf20Sopenharmony_ci skdev->timer_countdown--; 7568c2ecf20Sopenharmony_ci return; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY: 7628c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_IMMINENT: 7638c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_ERASE: 7648c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "busy[%x], countdown=%d\n", 7658c2ecf20Sopenharmony_ci skdev->state, skdev->timer_countdown); 7668c2ecf20Sopenharmony_ci if (skdev->timer_countdown > 0) { 7678c2ecf20Sopenharmony_ci skdev->timer_countdown--; 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 7718c2ecf20Sopenharmony_ci "busy[%x], timedout=%d, restarting device.", 7728c2ecf20Sopenharmony_ci skdev->state, skdev->timer_countdown); 7738c2ecf20Sopenharmony_ci skd_restart_device(skdev); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_WAIT_BOOT: 7778c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 7788c2ecf20Sopenharmony_ci if (skdev->timer_countdown > 0) { 7798c2ecf20Sopenharmony_ci skdev->timer_countdown--; 7808c2ecf20Sopenharmony_ci return; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci /* For now, we fault the drive. Could attempt resets to 7838c2ecf20Sopenharmony_ci * revcover at some point. */ 7848c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_FAULT; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "DriveFault Connect Timeout (%x)\n", 7878c2ecf20Sopenharmony_ci skdev->drive_state); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /*start the queue so we can respond with error to requests */ 7908c2ecf20Sopenharmony_ci /* wakeup anyone waiting for startup complete */ 7918c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 7928c2ecf20Sopenharmony_ci skdev->gendisk_on = -1; 7938c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_ONLINE: 7978c2ecf20Sopenharmony_ci /* shouldn't get here. */ 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSING: 8018c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSED: 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 8058c2ecf20Sopenharmony_ci if (skdev->timer_countdown > 0) { 8068c2ecf20Sopenharmony_ci skdev->timer_countdown--; 8078c2ecf20Sopenharmony_ci return; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci /* For now, we fault the drive. Could attempt resets to 8108c2ecf20Sopenharmony_ci * revcover at some point. */ 8118c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_FAULT; 8128c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 8138c2ecf20Sopenharmony_ci "DriveFault Reconnect Timeout (%x)\n", 8148c2ecf20Sopenharmony_ci skdev->drive_state); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* 8178c2ecf20Sopenharmony_ci * Recovering does two things: 8188c2ecf20Sopenharmony_ci * 1. completes IO with error 8198c2ecf20Sopenharmony_ci * 2. reclaims dma resources 8208c2ecf20Sopenharmony_ci * When is it safe to recover requests? 8218c2ecf20Sopenharmony_ci * - if the drive state is faulted 8228c2ecf20Sopenharmony_ci * - if the state is still soft reset after out timeout 8238c2ecf20Sopenharmony_ci * - if the drive registers are dead (state = FF) 8248c2ecf20Sopenharmony_ci * If it is "unsafe", we still need to recover, so we will 8258c2ecf20Sopenharmony_ci * disable pci bus mastering and disable our interrupts. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if ((skdev->drive_state == FIT_SR_DRIVE_SOFT_RESET) || 8298c2ecf20Sopenharmony_ci (skdev->drive_state == FIT_SR_DRIVE_FAULT) || 8308c2ecf20Sopenharmony_ci (skdev->drive_state == FIT_SR_DRIVE_STATE_MASK)) 8318c2ecf20Sopenharmony_ci /* It never came out of soft reset. Try to 8328c2ecf20Sopenharmony_ci * recover the requests and then let them 8338c2ecf20Sopenharmony_ci * fail. This is to mitigate hung processes. */ 8348c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 8358c2ecf20Sopenharmony_ci else { 8368c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Disable BusMaster (%x)\n", 8378c2ecf20Sopenharmony_ci skdev->drive_state); 8388c2ecf20Sopenharmony_ci pci_disable_device(skdev->pdev); 8398c2ecf20Sopenharmony_ci skd_disable_interrupts(skdev); 8408c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /*start the queue so we can respond with error to requests */ 8448c2ecf20Sopenharmony_ci /* wakeup anyone waiting for startup complete */ 8458c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 8468c2ecf20Sopenharmony_ci skdev->gendisk_on = -1; 8478c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESUMING: 8518c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STOPPING: 8528c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_SYNCING: 8538c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_FAULT: 8548c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_DISAPPEARED: 8558c2ecf20Sopenharmony_ci default: 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int skd_start_timer(struct skd_device *skdev) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci int rc; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci timer_setup(&skdev->timer, skd_timer_tick, 0); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci rc = mod_timer(&skdev->timer, (jiffies + HZ)); 8678c2ecf20Sopenharmony_ci if (rc) 8688c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "failed to start timer %d\n", rc); 8698c2ecf20Sopenharmony_ci return rc; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic void skd_kill_timer(struct skd_device *skdev) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci del_timer_sync(&skdev->timer); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/* 8788c2ecf20Sopenharmony_ci ***************************************************************************** 8798c2ecf20Sopenharmony_ci * INTERNAL REQUESTS -- generated by driver itself 8808c2ecf20Sopenharmony_ci ***************************************************************************** 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int skd_format_internal_skspcl(struct skd_device *skdev) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct skd_special_context *skspcl = &skdev->internal_skspcl; 8868c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; 8878c2ecf20Sopenharmony_ci struct fit_msg_hdr *fmh; 8888c2ecf20Sopenharmony_ci uint64_t dma_address; 8898c2ecf20Sopenharmony_ci struct skd_scsi_request *scsi; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci fmh = &skspcl->msg_buf->fmh; 8928c2ecf20Sopenharmony_ci fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; 8938c2ecf20Sopenharmony_ci fmh->num_protocol_cmds_coalesced = 1; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci scsi = &skspcl->msg_buf->scsi[0]; 8968c2ecf20Sopenharmony_ci memset(scsi, 0, sizeof(*scsi)); 8978c2ecf20Sopenharmony_ci dma_address = skspcl->req.sksg_dma_address; 8988c2ecf20Sopenharmony_ci scsi->hdr.sg_list_dma_address = cpu_to_be64(dma_address); 8998c2ecf20Sopenharmony_ci skspcl->req.n_sg = 1; 9008c2ecf20Sopenharmony_ci sgd->control = FIT_SGD_CONTROL_LAST; 9018c2ecf20Sopenharmony_ci sgd->byte_count = 0; 9028c2ecf20Sopenharmony_ci sgd->host_side_addr = skspcl->db_dma_address; 9038c2ecf20Sopenharmony_ci sgd->dev_side_addr = 0; 9048c2ecf20Sopenharmony_ci sgd->next_desc_ptr = 0LL; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return 1; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci#define WR_BUF_SIZE SKD_N_INTERNAL_BYTES 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void skd_send_internal_skspcl(struct skd_device *skdev, 9128c2ecf20Sopenharmony_ci struct skd_special_context *skspcl, 9138c2ecf20Sopenharmony_ci u8 opcode) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; 9168c2ecf20Sopenharmony_ci struct skd_scsi_request *scsi; 9178c2ecf20Sopenharmony_ci unsigned char *buf = skspcl->data_buf; 9188c2ecf20Sopenharmony_ci int i; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (skspcl->req.state != SKD_REQ_STATE_IDLE) 9218c2ecf20Sopenharmony_ci /* 9228c2ecf20Sopenharmony_ci * A refresh is already in progress. 9238c2ecf20Sopenharmony_ci * Just wait for it to finish. 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_ci return; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci skspcl->req.state = SKD_REQ_STATE_BUSY; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci scsi = &skspcl->msg_buf->scsi[0]; 9308c2ecf20Sopenharmony_ci scsi->hdr.tag = skspcl->req.id; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci memset(scsi->cdb, 0, sizeof(scsi->cdb)); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci switch (opcode) { 9358c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 9368c2ecf20Sopenharmony_ci scsi->cdb[0] = TEST_UNIT_READY; 9378c2ecf20Sopenharmony_ci sgd->byte_count = 0; 9388c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = 0; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci case READ_CAPACITY: 9428c2ecf20Sopenharmony_ci scsi->cdb[0] = READ_CAPACITY; 9438c2ecf20Sopenharmony_ci sgd->byte_count = SKD_N_READ_CAP_BYTES; 9448c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci case INQUIRY: 9488c2ecf20Sopenharmony_ci scsi->cdb[0] = INQUIRY; 9498c2ecf20Sopenharmony_ci scsi->cdb[1] = 0x01; /* evpd */ 9508c2ecf20Sopenharmony_ci scsi->cdb[2] = 0x80; /* serial number page */ 9518c2ecf20Sopenharmony_ci scsi->cdb[4] = 0x10; 9528c2ecf20Sopenharmony_ci sgd->byte_count = 16; 9538c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci case SYNCHRONIZE_CACHE: 9578c2ecf20Sopenharmony_ci scsi->cdb[0] = SYNCHRONIZE_CACHE; 9588c2ecf20Sopenharmony_ci sgd->byte_count = 0; 9598c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = 0; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci case WRITE_BUFFER: 9638c2ecf20Sopenharmony_ci scsi->cdb[0] = WRITE_BUFFER; 9648c2ecf20Sopenharmony_ci scsi->cdb[1] = 0x02; 9658c2ecf20Sopenharmony_ci scsi->cdb[7] = (WR_BUF_SIZE & 0xFF00) >> 8; 9668c2ecf20Sopenharmony_ci scsi->cdb[8] = WR_BUF_SIZE & 0xFF; 9678c2ecf20Sopenharmony_ci sgd->byte_count = WR_BUF_SIZE; 9688c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 9698c2ecf20Sopenharmony_ci /* fill incrementing byte pattern */ 9708c2ecf20Sopenharmony_ci for (i = 0; i < sgd->byte_count; i++) 9718c2ecf20Sopenharmony_ci buf[i] = i & 0xFF; 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci case READ_BUFFER: 9758c2ecf20Sopenharmony_ci scsi->cdb[0] = READ_BUFFER; 9768c2ecf20Sopenharmony_ci scsi->cdb[1] = 0x02; 9778c2ecf20Sopenharmony_ci scsi->cdb[7] = (WR_BUF_SIZE & 0xFF00) >> 8; 9788c2ecf20Sopenharmony_ci scsi->cdb[8] = WR_BUF_SIZE & 0xFF; 9798c2ecf20Sopenharmony_ci sgd->byte_count = WR_BUF_SIZE; 9808c2ecf20Sopenharmony_ci scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 9818c2ecf20Sopenharmony_ci memset(skspcl->data_buf, 0, sgd->byte_count); 9828c2ecf20Sopenharmony_ci break; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci default: 9858c2ecf20Sopenharmony_ci SKD_ASSERT("Don't know what to send"); 9868c2ecf20Sopenharmony_ci return; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci skd_send_special_fitmsg(skdev, skspcl); 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic void skd_refresh_device_data(struct skd_device *skdev) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci struct skd_special_context *skspcl = &skdev->internal_skspcl; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, TEST_UNIT_READY); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic int skd_chk_read_buf(struct skd_device *skdev, 10008c2ecf20Sopenharmony_ci struct skd_special_context *skspcl) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci unsigned char *buf = skspcl->data_buf; 10038c2ecf20Sopenharmony_ci int i; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* check for incrementing byte pattern */ 10068c2ecf20Sopenharmony_ci for (i = 0; i < WR_BUF_SIZE; i++) 10078c2ecf20Sopenharmony_ci if (buf[i] != (i & 0xFF)) 10088c2ecf20Sopenharmony_ci return 1; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic void skd_log_check_status(struct skd_device *skdev, u8 status, u8 key, 10148c2ecf20Sopenharmony_ci u8 code, u8 qual, u8 fruc) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci /* If the check condition is of special interest, log a message */ 10178c2ecf20Sopenharmony_ci if ((status == SAM_STAT_CHECK_CONDITION) && (key == 0x02) 10188c2ecf20Sopenharmony_ci && (code == 0x04) && (qual == 0x06)) { 10198c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 10208c2ecf20Sopenharmony_ci "*** LOST_WRITE_DATA ERROR *** key/asc/ascq/fruc %02x/%02x/%02x/%02x\n", 10218c2ecf20Sopenharmony_ci key, code, qual, fruc); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic void skd_complete_internal(struct skd_device *skdev, 10268c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcomp, 10278c2ecf20Sopenharmony_ci struct fit_comp_error_info *skerr, 10288c2ecf20Sopenharmony_ci struct skd_special_context *skspcl) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci u8 *buf = skspcl->data_buf; 10318c2ecf20Sopenharmony_ci u8 status; 10328c2ecf20Sopenharmony_ci int i; 10338c2ecf20Sopenharmony_ci struct skd_scsi_request *scsi = &skspcl->msg_buf->scsi[0]; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci lockdep_assert_held(&skdev->lock); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci SKD_ASSERT(skspcl == &skdev->internal_skspcl); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "complete internal %x\n", scsi->cdb[0]); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&skdev->pdev->dev, 10428c2ecf20Sopenharmony_ci skspcl->db_dma_address, 10438c2ecf20Sopenharmony_ci skspcl->req.sksg_list[0].byte_count, 10448c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci skspcl->req.completion = *skcomp; 10478c2ecf20Sopenharmony_ci skspcl->req.state = SKD_REQ_STATE_IDLE; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci status = skspcl->req.completion.status; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci skd_log_check_status(skdev, status, skerr->key, skerr->code, 10528c2ecf20Sopenharmony_ci skerr->qual, skerr->fruc); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci switch (scsi->cdb[0]) { 10558c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 10568c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) 10578c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, WRITE_BUFFER); 10588c2ecf20Sopenharmony_ci else if ((status == SAM_STAT_CHECK_CONDITION) && 10598c2ecf20Sopenharmony_ci (skerr->key == MEDIUM_ERROR)) 10608c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, WRITE_BUFFER); 10618c2ecf20Sopenharmony_ci else { 10628c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_STOPPING) { 10638c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 10648c2ecf20Sopenharmony_ci "TUR failed, don't send anymore state 0x%x\n", 10658c2ecf20Sopenharmony_ci skdev->state); 10668c2ecf20Sopenharmony_ci return; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 10698c2ecf20Sopenharmony_ci "**** TUR failed, retry skerr\n"); 10708c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, 10718c2ecf20Sopenharmony_ci TEST_UNIT_READY); 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci case WRITE_BUFFER: 10768c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) 10778c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, READ_BUFFER); 10788c2ecf20Sopenharmony_ci else { 10798c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_STOPPING) { 10808c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 10818c2ecf20Sopenharmony_ci "write buffer failed, don't send anymore state 0x%x\n", 10828c2ecf20Sopenharmony_ci skdev->state); 10838c2ecf20Sopenharmony_ci return; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 10868c2ecf20Sopenharmony_ci "**** write buffer failed, retry skerr\n"); 10878c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, 10888c2ecf20Sopenharmony_ci TEST_UNIT_READY); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci case READ_BUFFER: 10938c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) { 10948c2ecf20Sopenharmony_ci if (skd_chk_read_buf(skdev, skspcl) == 0) 10958c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, 10968c2ecf20Sopenharmony_ci READ_CAPACITY); 10978c2ecf20Sopenharmony_ci else { 10988c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 10998c2ecf20Sopenharmony_ci "*** W/R Buffer mismatch %d ***\n", 11008c2ecf20Sopenharmony_ci skdev->connect_retries); 11018c2ecf20Sopenharmony_ci if (skdev->connect_retries < 11028c2ecf20Sopenharmony_ci SKD_MAX_CONNECT_RETRIES) { 11038c2ecf20Sopenharmony_ci skdev->connect_retries++; 11048c2ecf20Sopenharmony_ci skd_soft_reset(skdev); 11058c2ecf20Sopenharmony_ci } else { 11068c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 11078c2ecf20Sopenharmony_ci "W/R Buffer Connect Error\n"); 11088c2ecf20Sopenharmony_ci return; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_STOPPING) { 11148c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 11158c2ecf20Sopenharmony_ci "read buffer failed, don't send anymore state 0x%x\n", 11168c2ecf20Sopenharmony_ci skdev->state); 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 11208c2ecf20Sopenharmony_ci "**** read buffer failed, retry skerr\n"); 11218c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, 11228c2ecf20Sopenharmony_ci TEST_UNIT_READY); 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci case READ_CAPACITY: 11278c2ecf20Sopenharmony_ci skdev->read_cap_is_valid = 0; 11288c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) { 11298c2ecf20Sopenharmony_ci skdev->read_cap_last_lba = 11308c2ecf20Sopenharmony_ci (buf[0] << 24) | (buf[1] << 16) | 11318c2ecf20Sopenharmony_ci (buf[2] << 8) | buf[3]; 11328c2ecf20Sopenharmony_ci skdev->read_cap_blocksize = 11338c2ecf20Sopenharmony_ci (buf[4] << 24) | (buf[5] << 16) | 11348c2ecf20Sopenharmony_ci (buf[6] << 8) | buf[7]; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "last lba %d, bs %d\n", 11378c2ecf20Sopenharmony_ci skdev->read_cap_last_lba, 11388c2ecf20Sopenharmony_ci skdev->read_cap_blocksize); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci skdev->read_cap_is_valid = 1; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, INQUIRY); 11458c2ecf20Sopenharmony_ci } else if ((status == SAM_STAT_CHECK_CONDITION) && 11468c2ecf20Sopenharmony_ci (skerr->key == MEDIUM_ERROR)) { 11478c2ecf20Sopenharmony_ci skdev->read_cap_last_lba = ~0; 11488c2ecf20Sopenharmony_ci set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); 11498c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "**** MEDIUM ERROR caused READCAP to fail, ignore failure and continue to inquiry\n"); 11508c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, INQUIRY); 11518c2ecf20Sopenharmony_ci } else { 11528c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "**** READCAP failed, retry TUR\n"); 11538c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, 11548c2ecf20Sopenharmony_ci TEST_UNIT_READY); 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci case INQUIRY: 11598c2ecf20Sopenharmony_ci skdev->inquiry_is_valid = 0; 11608c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) { 11618c2ecf20Sopenharmony_ci skdev->inquiry_is_valid = 1; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci for (i = 0; i < 12; i++) 11648c2ecf20Sopenharmony_ci skdev->inq_serial_num[i] = buf[i + 4]; 11658c2ecf20Sopenharmony_ci skdev->inq_serial_num[12] = 0; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (skd_unquiesce_dev(skdev) < 0) 11698c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "**** failed, to ONLINE device\n"); 11708c2ecf20Sopenharmony_ci /* connection is complete */ 11718c2ecf20Sopenharmony_ci skdev->connect_retries = 0; 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci case SYNCHRONIZE_CACHE: 11758c2ecf20Sopenharmony_ci if (status == SAM_STAT_GOOD) 11768c2ecf20Sopenharmony_ci skdev->sync_done = 1; 11778c2ecf20Sopenharmony_ci else 11788c2ecf20Sopenharmony_ci skdev->sync_done = -1; 11798c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci default: 11838c2ecf20Sopenharmony_ci SKD_ASSERT("we didn't send this"); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci/* 11888c2ecf20Sopenharmony_ci ***************************************************************************** 11898c2ecf20Sopenharmony_ci * FIT MESSAGES 11908c2ecf20Sopenharmony_ci ***************************************************************************** 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic void skd_send_fitmsg(struct skd_device *skdev, 11948c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci u64 qcmd; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "dma address %pad, busy=%d\n", 11998c2ecf20Sopenharmony_ci &skmsg->mb_dma_address, skd_in_flight(skdev)); 12008c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "msg_buf %p\n", skmsg->msg_buf); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci qcmd = skmsg->mb_dma_address; 12038c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_QID_NORMAL; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level > 1)) { 12068c2ecf20Sopenharmony_ci u8 *bp = (u8 *)skmsg->msg_buf; 12078c2ecf20Sopenharmony_ci int i; 12088c2ecf20Sopenharmony_ci for (i = 0; i < skmsg->length; i += 8) { 12098c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "msg[%2d] %8ph\n", i, 12108c2ecf20Sopenharmony_ci &bp[i]); 12118c2ecf20Sopenharmony_ci if (i == 0) 12128c2ecf20Sopenharmony_ci i = 64 - 8; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (skmsg->length > 256) 12178c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_MSGSIZE_512; 12188c2ecf20Sopenharmony_ci else if (skmsg->length > 128) 12198c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_MSGSIZE_256; 12208c2ecf20Sopenharmony_ci else if (skmsg->length > 64) 12218c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_MSGSIZE_128; 12228c2ecf20Sopenharmony_ci else 12238c2ecf20Sopenharmony_ci /* 12248c2ecf20Sopenharmony_ci * This makes no sense because the FIT msg header is 12258c2ecf20Sopenharmony_ci * 64 bytes. If the msg is only 64 bytes long it has 12268c2ecf20Sopenharmony_ci * no payload. 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_MSGSIZE_64; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci dma_sync_single_for_device(&skdev->pdev->dev, skmsg->mb_dma_address, 12318c2ecf20Sopenharmony_ci skmsg->length, DMA_TO_DEVICE); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* Make sure skd_msg_buf is written before the doorbell is triggered. */ 12348c2ecf20Sopenharmony_ci smp_wmb(); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic void skd_send_special_fitmsg(struct skd_device *skdev, 12408c2ecf20Sopenharmony_ci struct skd_special_context *skspcl) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci u64 qcmd; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci WARN_ON_ONCE(skspcl->req.n_sg != 1); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (unlikely(skdev->dbg_level > 1)) { 12478c2ecf20Sopenharmony_ci u8 *bp = (u8 *)skspcl->msg_buf; 12488c2ecf20Sopenharmony_ci int i; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) { 12518c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " spcl[%2d] %8ph\n", i, 12528c2ecf20Sopenharmony_ci &bp[i]); 12538c2ecf20Sopenharmony_ci if (i == 0) 12548c2ecf20Sopenharmony_ci i = 64 - 8; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 12588c2ecf20Sopenharmony_ci "skspcl=%p id=%04x sksg_list=%p sksg_dma=%pad\n", 12598c2ecf20Sopenharmony_ci skspcl, skspcl->req.id, skspcl->req.sksg_list, 12608c2ecf20Sopenharmony_ci &skspcl->req.sksg_dma_address); 12618c2ecf20Sopenharmony_ci for (i = 0; i < skspcl->req.n_sg; i++) { 12628c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sgd = 12638c2ecf20Sopenharmony_ci &skspcl->req.sksg_list[i]; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 12668c2ecf20Sopenharmony_ci " sg[%d] count=%u ctrl=0x%x addr=0x%llx next=0x%llx\n", 12678c2ecf20Sopenharmony_ci i, sgd->byte_count, sgd->control, 12688c2ecf20Sopenharmony_ci sgd->host_side_addr, sgd->next_desc_ptr); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* 12738c2ecf20Sopenharmony_ci * Special FIT msgs are always 128 bytes: a 64-byte FIT hdr 12748c2ecf20Sopenharmony_ci * and one 64-byte SSDI command. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci qcmd = skspcl->mb_dma_address; 12778c2ecf20Sopenharmony_ci qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci dma_sync_single_for_device(&skdev->pdev->dev, skspcl->mb_dma_address, 12808c2ecf20Sopenharmony_ci SKD_N_SPECIAL_FITMSG_BYTES, DMA_TO_DEVICE); 12818c2ecf20Sopenharmony_ci dma_sync_single_for_device(&skdev->pdev->dev, 12828c2ecf20Sopenharmony_ci skspcl->req.sksg_dma_address, 12838c2ecf20Sopenharmony_ci 1 * sizeof(struct fit_sg_descriptor), 12848c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12858c2ecf20Sopenharmony_ci dma_sync_single_for_device(&skdev->pdev->dev, 12868c2ecf20Sopenharmony_ci skspcl->db_dma_address, 12878c2ecf20Sopenharmony_ci skspcl->req.sksg_list[0].byte_count, 12888c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* Make sure skd_msg_buf is written before the doorbell is triggered. */ 12918c2ecf20Sopenharmony_ci smp_wmb(); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci/* 12978c2ecf20Sopenharmony_ci ***************************************************************************** 12988c2ecf20Sopenharmony_ci * COMPLETION QUEUE 12998c2ecf20Sopenharmony_ci ***************************************************************************** 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic void skd_complete_other(struct skd_device *skdev, 13038c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcomp, 13048c2ecf20Sopenharmony_ci struct fit_comp_error_info *skerr); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistruct sns_info { 13078c2ecf20Sopenharmony_ci u8 type; 13088c2ecf20Sopenharmony_ci u8 stat; 13098c2ecf20Sopenharmony_ci u8 key; 13108c2ecf20Sopenharmony_ci u8 asc; 13118c2ecf20Sopenharmony_ci u8 ascq; 13128c2ecf20Sopenharmony_ci u8 mask; 13138c2ecf20Sopenharmony_ci enum skd_check_status_action action; 13148c2ecf20Sopenharmony_ci}; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic struct sns_info skd_chkstat_table[] = { 13178c2ecf20Sopenharmony_ci /* Good */ 13188c2ecf20Sopenharmony_ci { 0x70, 0x02, RECOVERED_ERROR, 0, 0, 0x1c, 13198c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_GOOD }, 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* Smart alerts */ 13228c2ecf20Sopenharmony_ci { 0x70, 0x02, NO_SENSE, 0x0B, 0x00, 0x1E, /* warnings */ 13238c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_SMART_ALERT }, 13248c2ecf20Sopenharmony_ci { 0x70, 0x02, NO_SENSE, 0x5D, 0x00, 0x1E, /* thresholds */ 13258c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_SMART_ALERT }, 13268c2ecf20Sopenharmony_ci { 0x70, 0x02, RECOVERED_ERROR, 0x0B, 0x01, 0x1F, /* temperature over trigger */ 13278c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REPORT_SMART_ALERT }, 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* Retry (with limits) */ 13308c2ecf20Sopenharmony_ci { 0x70, 0x02, 0x0B, 0, 0, 0x1C, /* This one is for DMA ERROR */ 13318c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REQUEUE_REQUEST }, 13328c2ecf20Sopenharmony_ci { 0x70, 0x02, 0x06, 0x0B, 0x00, 0x1E, /* warnings */ 13338c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REQUEUE_REQUEST }, 13348c2ecf20Sopenharmony_ci { 0x70, 0x02, 0x06, 0x5D, 0x00, 0x1E, /* thresholds */ 13358c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REQUEUE_REQUEST }, 13368c2ecf20Sopenharmony_ci { 0x70, 0x02, 0x06, 0x80, 0x30, 0x1F, /* backup power */ 13378c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_REQUEUE_REQUEST }, 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* Busy (or about to be) */ 13408c2ecf20Sopenharmony_ci { 0x70, 0x02, 0x06, 0x3f, 0x01, 0x1F, /* fw changed */ 13418c2ecf20Sopenharmony_ci SKD_CHECK_STATUS_BUSY_IMMINENT }, 13428c2ecf20Sopenharmony_ci}; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci/* 13458c2ecf20Sopenharmony_ci * Look up status and sense data to decide how to handle the error 13468c2ecf20Sopenharmony_ci * from the device. 13478c2ecf20Sopenharmony_ci * mask says which fields must match e.g., mask=0x18 means check 13488c2ecf20Sopenharmony_ci * type and stat, ignore key, asc, ascq. 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic enum skd_check_status_action 13528c2ecf20Sopenharmony_ciskd_check_status(struct skd_device *skdev, 13538c2ecf20Sopenharmony_ci u8 cmp_status, struct fit_comp_error_info *skerr) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci int i; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "key/asc/ascq/fruc %02x/%02x/%02x/%02x\n", 13588c2ecf20Sopenharmony_ci skerr->key, skerr->code, skerr->qual, skerr->fruc); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 13618c2ecf20Sopenharmony_ci "stat: t=%02x stat=%02x k=%02x c=%02x q=%02x fruc=%02x\n", 13628c2ecf20Sopenharmony_ci skerr->type, cmp_status, skerr->key, skerr->code, skerr->qual, 13638c2ecf20Sopenharmony_ci skerr->fruc); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* Does the info match an entry in the good category? */ 13668c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(skd_chkstat_table); i++) { 13678c2ecf20Sopenharmony_ci struct sns_info *sns = &skd_chkstat_table[i]; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (sns->mask & 0x10) 13708c2ecf20Sopenharmony_ci if (skerr->type != sns->type) 13718c2ecf20Sopenharmony_ci continue; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (sns->mask & 0x08) 13748c2ecf20Sopenharmony_ci if (cmp_status != sns->stat) 13758c2ecf20Sopenharmony_ci continue; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (sns->mask & 0x04) 13788c2ecf20Sopenharmony_ci if (skerr->key != sns->key) 13798c2ecf20Sopenharmony_ci continue; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (sns->mask & 0x02) 13828c2ecf20Sopenharmony_ci if (skerr->code != sns->asc) 13838c2ecf20Sopenharmony_ci continue; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (sns->mask & 0x01) 13868c2ecf20Sopenharmony_ci if (skerr->qual != sns->ascq) 13878c2ecf20Sopenharmony_ci continue; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (sns->action == SKD_CHECK_STATUS_REPORT_SMART_ALERT) { 13908c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 13918c2ecf20Sopenharmony_ci "SMART Alert: sense key/asc/ascq %02x/%02x/%02x\n", 13928c2ecf20Sopenharmony_ci skerr->key, skerr->code, skerr->qual); 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci return sns->action; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* No other match, so nonzero status means error, 13988c2ecf20Sopenharmony_ci * zero status means good 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_ci if (cmp_status) { 14018c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "status check: error\n"); 14028c2ecf20Sopenharmony_ci return SKD_CHECK_STATUS_REPORT_ERROR; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "status check good default\n"); 14068c2ecf20Sopenharmony_ci return SKD_CHECK_STATUS_REPORT_GOOD; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic void skd_resolve_req_exception(struct skd_device *skdev, 14108c2ecf20Sopenharmony_ci struct skd_request_context *skreq, 14118c2ecf20Sopenharmony_ci struct request *req) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci u8 cmp_status = skreq->completion.status; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci switch (skd_check_status(skdev, cmp_status, &skreq->err_info)) { 14168c2ecf20Sopenharmony_ci case SKD_CHECK_STATUS_REPORT_GOOD: 14178c2ecf20Sopenharmony_ci case SKD_CHECK_STATUS_REPORT_SMART_ALERT: 14188c2ecf20Sopenharmony_ci skreq->status = BLK_STS_OK; 14198c2ecf20Sopenharmony_ci if (likely(!blk_should_fake_timeout(req->q))) 14208c2ecf20Sopenharmony_ci blk_mq_complete_request(req); 14218c2ecf20Sopenharmony_ci break; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci case SKD_CHECK_STATUS_BUSY_IMMINENT: 14248c2ecf20Sopenharmony_ci skd_log_skreq(skdev, skreq, "retry(busy)"); 14258c2ecf20Sopenharmony_ci blk_mq_requeue_request(req, true); 14268c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, "drive BUSY imminent\n"); 14278c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT; 14288c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_TIMER_MINUTES(20); 14298c2ecf20Sopenharmony_ci skd_quiesce_dev(skdev); 14308c2ecf20Sopenharmony_ci break; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci case SKD_CHECK_STATUS_REQUEUE_REQUEST: 14338c2ecf20Sopenharmony_ci if (++skreq->retries < SKD_MAX_RETRIES) { 14348c2ecf20Sopenharmony_ci skd_log_skreq(skdev, skreq, "retry"); 14358c2ecf20Sopenharmony_ci blk_mq_requeue_request(req, true); 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci fallthrough; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci case SKD_CHECK_STATUS_REPORT_ERROR: 14418c2ecf20Sopenharmony_ci default: 14428c2ecf20Sopenharmony_ci skreq->status = BLK_STS_IOERR; 14438c2ecf20Sopenharmony_ci if (likely(!blk_should_fake_timeout(req->q))) 14448c2ecf20Sopenharmony_ci blk_mq_complete_request(req); 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic void skd_release_skreq(struct skd_device *skdev, 14508c2ecf20Sopenharmony_ci struct skd_request_context *skreq) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci /* 14538c2ecf20Sopenharmony_ci * Reclaim the skd_request_context 14548c2ecf20Sopenharmony_ci */ 14558c2ecf20Sopenharmony_ci skreq->state = SKD_REQ_STATE_IDLE; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic int skd_isr_completion_posted(struct skd_device *skdev, 14598c2ecf20Sopenharmony_ci int limit, int *enqueued) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcmp; 14628c2ecf20Sopenharmony_ci struct fit_comp_error_info *skerr; 14638c2ecf20Sopenharmony_ci u16 req_id; 14648c2ecf20Sopenharmony_ci u32 tag; 14658c2ecf20Sopenharmony_ci u16 hwq = 0; 14668c2ecf20Sopenharmony_ci struct request *rq; 14678c2ecf20Sopenharmony_ci struct skd_request_context *skreq; 14688c2ecf20Sopenharmony_ci u16 cmp_cntxt; 14698c2ecf20Sopenharmony_ci u8 cmp_status; 14708c2ecf20Sopenharmony_ci u8 cmp_cycle; 14718c2ecf20Sopenharmony_ci u32 cmp_bytes; 14728c2ecf20Sopenharmony_ci int rc = 0; 14738c2ecf20Sopenharmony_ci int processed = 0; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci lockdep_assert_held(&skdev->lock); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci for (;; ) { 14788c2ecf20Sopenharmony_ci SKD_ASSERT(skdev->skcomp_ix < SKD_N_COMPLETION_ENTRY); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci skcmp = &skdev->skcomp_table[skdev->skcomp_ix]; 14818c2ecf20Sopenharmony_ci cmp_cycle = skcmp->cycle; 14828c2ecf20Sopenharmony_ci cmp_cntxt = skcmp->tag; 14838c2ecf20Sopenharmony_ci cmp_status = skcmp->status; 14848c2ecf20Sopenharmony_ci cmp_bytes = be32_to_cpu(skcmp->num_returned_bytes); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci skerr = &skdev->skerr_table[skdev->skcomp_ix]; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 14898c2ecf20Sopenharmony_ci "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d busy=%d rbytes=0x%x proto=%d\n", 14908c2ecf20Sopenharmony_ci skdev->skcomp_cycle, skdev->skcomp_ix, cmp_cycle, 14918c2ecf20Sopenharmony_ci cmp_cntxt, cmp_status, skd_in_flight(skdev), 14928c2ecf20Sopenharmony_ci cmp_bytes, skdev->proto_ver); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (cmp_cycle != skdev->skcomp_cycle) { 14958c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "end of completions\n"); 14968c2ecf20Sopenharmony_ci break; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci /* 14998c2ecf20Sopenharmony_ci * Update the completion queue head index and possibly 15008c2ecf20Sopenharmony_ci * the completion cycle count. 8-bit wrap-around. 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci skdev->skcomp_ix++; 15038c2ecf20Sopenharmony_ci if (skdev->skcomp_ix >= SKD_N_COMPLETION_ENTRY) { 15048c2ecf20Sopenharmony_ci skdev->skcomp_ix = 0; 15058c2ecf20Sopenharmony_ci skdev->skcomp_cycle++; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* 15098c2ecf20Sopenharmony_ci * The command context is a unique 32-bit ID. The low order 15108c2ecf20Sopenharmony_ci * bits help locate the request. The request is usually a 15118c2ecf20Sopenharmony_ci * r/w request (see skd_start() above) or a special request. 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_ci req_id = cmp_cntxt; 15148c2ecf20Sopenharmony_ci tag = req_id & SKD_ID_SLOT_AND_TABLE_MASK; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* Is this other than a r/w request? */ 15178c2ecf20Sopenharmony_ci if (tag >= skdev->num_req_context) { 15188c2ecf20Sopenharmony_ci /* 15198c2ecf20Sopenharmony_ci * This is not a completion for a r/w request. 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_ci WARN_ON_ONCE(blk_mq_tag_to_rq(skdev->tag_set.tags[hwq], 15228c2ecf20Sopenharmony_ci tag)); 15238c2ecf20Sopenharmony_ci skd_complete_other(skdev, skcmp, skerr); 15248c2ecf20Sopenharmony_ci continue; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci rq = blk_mq_tag_to_rq(skdev->tag_set.tags[hwq], tag); 15288c2ecf20Sopenharmony_ci if (WARN(!rq, "No request for tag %#x -> %#x\n", cmp_cntxt, 15298c2ecf20Sopenharmony_ci tag)) 15308c2ecf20Sopenharmony_ci continue; 15318c2ecf20Sopenharmony_ci skreq = blk_mq_rq_to_pdu(rq); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci /* 15348c2ecf20Sopenharmony_ci * Make sure the request ID for the slot matches. 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci if (skreq->id != req_id) { 15378c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 15388c2ecf20Sopenharmony_ci "Completion mismatch comp_id=0x%04x skreq=0x%04x new=0x%04x\n", 15398c2ecf20Sopenharmony_ci req_id, skreq->id, cmp_cntxt); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci continue; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci SKD_ASSERT(skreq->state == SKD_REQ_STATE_BUSY); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci skreq->completion = *skcmp; 15478c2ecf20Sopenharmony_ci if (unlikely(cmp_status == SAM_STAT_CHECK_CONDITION)) { 15488c2ecf20Sopenharmony_ci skreq->err_info = *skerr; 15498c2ecf20Sopenharmony_ci skd_log_check_status(skdev, cmp_status, skerr->key, 15508c2ecf20Sopenharmony_ci skerr->code, skerr->qual, 15518c2ecf20Sopenharmony_ci skerr->fruc); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci /* Release DMA resources for the request. */ 15548c2ecf20Sopenharmony_ci if (skreq->n_sg > 0) 15558c2ecf20Sopenharmony_ci skd_postop_sg_list(skdev, skreq); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci skd_release_skreq(skdev, skreq); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* 15608c2ecf20Sopenharmony_ci * Capture the outcome and post it back to the native request. 15618c2ecf20Sopenharmony_ci */ 15628c2ecf20Sopenharmony_ci if (likely(cmp_status == SAM_STAT_GOOD)) { 15638c2ecf20Sopenharmony_ci skreq->status = BLK_STS_OK; 15648c2ecf20Sopenharmony_ci if (likely(!blk_should_fake_timeout(rq->q))) 15658c2ecf20Sopenharmony_ci blk_mq_complete_request(rq); 15668c2ecf20Sopenharmony_ci } else { 15678c2ecf20Sopenharmony_ci skd_resolve_req_exception(skdev, skreq, rq); 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci /* skd_isr_comp_limit equal zero means no limit */ 15718c2ecf20Sopenharmony_ci if (limit) { 15728c2ecf20Sopenharmony_ci if (++processed >= limit) { 15738c2ecf20Sopenharmony_ci rc = 1; 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_PAUSING && 15808c2ecf20Sopenharmony_ci skd_in_flight(skdev) == 0) { 15818c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_PAUSED; 15828c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci return rc; 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_cistatic void skd_complete_other(struct skd_device *skdev, 15898c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcomp, 15908c2ecf20Sopenharmony_ci struct fit_comp_error_info *skerr) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci u32 req_id = 0; 15938c2ecf20Sopenharmony_ci u32 req_table; 15948c2ecf20Sopenharmony_ci u32 req_slot; 15958c2ecf20Sopenharmony_ci struct skd_special_context *skspcl; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci lockdep_assert_held(&skdev->lock); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci req_id = skcomp->tag; 16008c2ecf20Sopenharmony_ci req_table = req_id & SKD_ID_TABLE_MASK; 16018c2ecf20Sopenharmony_ci req_slot = req_id & SKD_ID_SLOT_MASK; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "table=0x%x id=0x%x slot=%d\n", req_table, 16048c2ecf20Sopenharmony_ci req_id, req_slot); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* 16078c2ecf20Sopenharmony_ci * Based on the request id, determine how to dispatch this completion. 16088c2ecf20Sopenharmony_ci * This swich/case is finding the good cases and forwarding the 16098c2ecf20Sopenharmony_ci * completion entry. Errors are reported below the switch. 16108c2ecf20Sopenharmony_ci */ 16118c2ecf20Sopenharmony_ci switch (req_table) { 16128c2ecf20Sopenharmony_ci case SKD_ID_RW_REQUEST: 16138c2ecf20Sopenharmony_ci /* 16148c2ecf20Sopenharmony_ci * The caller, skd_isr_completion_posted() above, 16158c2ecf20Sopenharmony_ci * handles r/w requests. The only way we get here 16168c2ecf20Sopenharmony_ci * is if the req_slot is out of bounds. 16178c2ecf20Sopenharmony_ci */ 16188c2ecf20Sopenharmony_ci break; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci case SKD_ID_INTERNAL: 16218c2ecf20Sopenharmony_ci if (req_slot == 0) { 16228c2ecf20Sopenharmony_ci skspcl = &skdev->internal_skspcl; 16238c2ecf20Sopenharmony_ci if (skspcl->req.id == req_id && 16248c2ecf20Sopenharmony_ci skspcl->req.state == SKD_REQ_STATE_BUSY) { 16258c2ecf20Sopenharmony_ci skd_complete_internal(skdev, 16268c2ecf20Sopenharmony_ci skcomp, skerr, skspcl); 16278c2ecf20Sopenharmony_ci return; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci break; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci case SKD_ID_FIT_MSG: 16338c2ecf20Sopenharmony_ci /* 16348c2ecf20Sopenharmony_ci * These id's should never appear in a completion record. 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_ci break; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci default: 16398c2ecf20Sopenharmony_ci /* 16408c2ecf20Sopenharmony_ci * These id's should never appear anywhere; 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ci break; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* 16468c2ecf20Sopenharmony_ci * If we get here it is a bad or stale id. 16478c2ecf20Sopenharmony_ci */ 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic void skd_reset_skcomp(struct skd_device *skdev) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci memset(skdev->skcomp_table, 0, SKD_SKCOMP_SIZE); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci skdev->skcomp_ix = 0; 16558c2ecf20Sopenharmony_ci skdev->skcomp_cycle = 1; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci/* 16598c2ecf20Sopenharmony_ci ***************************************************************************** 16608c2ecf20Sopenharmony_ci * INTERRUPTS 16618c2ecf20Sopenharmony_ci ***************************************************************************** 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_cistatic void skd_completion_worker(struct work_struct *work) 16648c2ecf20Sopenharmony_ci{ 16658c2ecf20Sopenharmony_ci struct skd_device *skdev = 16668c2ecf20Sopenharmony_ci container_of(work, struct skd_device, completion_worker); 16678c2ecf20Sopenharmony_ci unsigned long flags; 16688c2ecf20Sopenharmony_ci int flush_enqueued = 0; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* 16738c2ecf20Sopenharmony_ci * pass in limit=0, which means no limit.. 16748c2ecf20Sopenharmony_ci * process everything in compq 16758c2ecf20Sopenharmony_ci */ 16768c2ecf20Sopenharmony_ci skd_isr_completion_posted(skdev, 0, &flush_enqueued); 16778c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic void skd_isr_msg_from_dev(struct skd_device *skdev); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic irqreturn_t 16858c2ecf20Sopenharmony_ciskd_isr(int irq, void *ptr) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci struct skd_device *skdev = ptr; 16888c2ecf20Sopenharmony_ci u32 intstat; 16898c2ecf20Sopenharmony_ci u32 ack; 16908c2ecf20Sopenharmony_ci int rc = 0; 16918c2ecf20Sopenharmony_ci int deferred = 0; 16928c2ecf20Sopenharmony_ci int flush_enqueued = 0; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci spin_lock(&skdev->lock); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci for (;; ) { 16978c2ecf20Sopenharmony_ci intstat = SKD_READL(skdev, FIT_INT_STATUS_HOST); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci ack = FIT_INT_DEF_MASK; 17008c2ecf20Sopenharmony_ci ack &= intstat; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "intstat=0x%x ack=0x%x\n", intstat, 17038c2ecf20Sopenharmony_ci ack); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* As long as there is an int pending on device, keep 17068c2ecf20Sopenharmony_ci * running loop. When none, get out, but if we've never 17078c2ecf20Sopenharmony_ci * done any processing, call completion handler? 17088c2ecf20Sopenharmony_ci */ 17098c2ecf20Sopenharmony_ci if (ack == 0) { 17108c2ecf20Sopenharmony_ci /* No interrupts on device, but run the completion 17118c2ecf20Sopenharmony_ci * processor anyway? 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_ci if (rc == 0) 17148c2ecf20Sopenharmony_ci if (likely (skdev->state 17158c2ecf20Sopenharmony_ci == SKD_DRVR_STATE_ONLINE)) 17168c2ecf20Sopenharmony_ci deferred = 1; 17178c2ecf20Sopenharmony_ci break; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci rc = IRQ_HANDLED; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, ack, FIT_INT_STATUS_HOST); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (likely((skdev->state != SKD_DRVR_STATE_LOAD) && 17258c2ecf20Sopenharmony_ci (skdev->state != SKD_DRVR_STATE_STOPPING))) { 17268c2ecf20Sopenharmony_ci if (intstat & FIT_ISH_COMPLETION_POSTED) { 17278c2ecf20Sopenharmony_ci /* 17288c2ecf20Sopenharmony_ci * If we have already deferred completion 17298c2ecf20Sopenharmony_ci * processing, don't bother running it again 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci if (deferred == 0) 17328c2ecf20Sopenharmony_ci deferred = 17338c2ecf20Sopenharmony_ci skd_isr_completion_posted(skdev, 17348c2ecf20Sopenharmony_ci skd_isr_comp_limit, &flush_enqueued); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (intstat & FIT_ISH_FW_STATE_CHANGE) { 17388c2ecf20Sopenharmony_ci skd_isr_fwstate(skdev); 17398c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_FAULT || 17408c2ecf20Sopenharmony_ci skdev->state == 17418c2ecf20Sopenharmony_ci SKD_DRVR_STATE_DISAPPEARED) { 17428c2ecf20Sopenharmony_ci spin_unlock(&skdev->lock); 17438c2ecf20Sopenharmony_ci return rc; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (intstat & FIT_ISH_MSG_FROM_DEV) 17488c2ecf20Sopenharmony_ci skd_isr_msg_from_dev(skdev); 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (unlikely(flush_enqueued)) 17538c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (deferred) 17568c2ecf20Sopenharmony_ci schedule_work(&skdev->completion_worker); 17578c2ecf20Sopenharmony_ci else if (!flush_enqueued) 17588c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci spin_unlock(&skdev->lock); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci return rc; 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic void skd_drive_fault(struct skd_device *skdev) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_FAULT; 17688c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Drive FAULT\n"); 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic void skd_drive_disappeared(struct skd_device *skdev) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_DISAPPEARED; 17748c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Drive DISAPPEARED\n"); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic void skd_isr_fwstate(struct skd_device *skdev) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci u32 sense; 17808c2ecf20Sopenharmony_ci u32 state; 17818c2ecf20Sopenharmony_ci u32 mtd; 17828c2ecf20Sopenharmony_ci int prev_driver_state = skdev->state; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci sense = SKD_READL(skdev, FIT_STATUS); 17858c2ecf20Sopenharmony_ci state = sense & FIT_SR_DRIVE_STATE_MASK; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "s1120 state %s(%d)=>%s(%d)\n", 17888c2ecf20Sopenharmony_ci skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, 17898c2ecf20Sopenharmony_ci skd_drive_state_to_str(state), state); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci skdev->drive_state = state; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci switch (skdev->drive_state) { 17948c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_INIT: 17958c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_PROTOCOL_MISMATCH) { 17968c2ecf20Sopenharmony_ci skd_disable_interrupts(skdev); 17978c2ecf20Sopenharmony_ci break; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_RESTARTING) 18008c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 18018c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_WAIT_BOOT) { 18028c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_STARTING_TIMO; 18038c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_STARTING; 18048c2ecf20Sopenharmony_ci skd_soft_reset(skdev); 18058c2ecf20Sopenharmony_ci break; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_FITFW_INIT, 0, 0); 18088c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 18098c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 18108c2ecf20Sopenharmony_ci break; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_ONLINE: 18138c2ecf20Sopenharmony_ci skdev->cur_max_queue_depth = skd_max_queue_depth; 18148c2ecf20Sopenharmony_ci if (skdev->cur_max_queue_depth > skdev->dev_max_queue_depth) 18158c2ecf20Sopenharmony_ci skdev->cur_max_queue_depth = skdev->dev_max_queue_depth; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci skdev->queue_low_water_mark = 18188c2ecf20Sopenharmony_ci skdev->cur_max_queue_depth * 2 / 3 + 1; 18198c2ecf20Sopenharmony_ci if (skdev->queue_low_water_mark < 1) 18208c2ecf20Sopenharmony_ci skdev->queue_low_water_mark = 1; 18218c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, 18228c2ecf20Sopenharmony_ci "Queue depth limit=%d dev=%d lowat=%d\n", 18238c2ecf20Sopenharmony_ci skdev->cur_max_queue_depth, 18248c2ecf20Sopenharmony_ci skdev->dev_max_queue_depth, 18258c2ecf20Sopenharmony_ci skdev->queue_low_water_mark); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci skd_refresh_device_data(skdev); 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY: 18318c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY; 18328c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_BUSY_TIMO; 18338c2ecf20Sopenharmony_ci skd_quiesce_dev(skdev); 18348c2ecf20Sopenharmony_ci break; 18358c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_SANITIZE: 18368c2ecf20Sopenharmony_ci /* set timer for 3 seconds, we'll abort any unfinished 18378c2ecf20Sopenharmony_ci * commands after that expires 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; 18408c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_TIMER_SECONDS(3); 18418c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 18428c2ecf20Sopenharmony_ci break; 18438c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_ERASE: 18448c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY_ERASE; 18458c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_BUSY_TIMO; 18468c2ecf20Sopenharmony_ci break; 18478c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_OFFLINE: 18488c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_IDLE; 18498c2ecf20Sopenharmony_ci break; 18508c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_SOFT_RESET: 18518c2ecf20Sopenharmony_ci switch (skdev->state) { 18528c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 18538c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 18548c2ecf20Sopenharmony_ci /* Expected by a caller of skd_soft_reset() */ 18558c2ecf20Sopenharmony_ci break; 18568c2ecf20Sopenharmony_ci default: 18578c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_RESTARTING; 18588c2ecf20Sopenharmony_ci break; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci break; 18618c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FW_BOOTING: 18628c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "ISR FIT_SR_DRIVE_FW_BOOTING\n"); 18638c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_WAIT_BOOT; 18648c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; 18658c2ecf20Sopenharmony_ci break; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_DEGRADED: 18688c2ecf20Sopenharmony_ci case FIT_SR_PCIE_LINK_DOWN: 18698c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: 18708c2ecf20Sopenharmony_ci break; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FAULT: 18738c2ecf20Sopenharmony_ci skd_drive_fault(skdev); 18748c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 18758c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 18768c2ecf20Sopenharmony_ci break; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* PCIe bus returned all Fs? */ 18798c2ecf20Sopenharmony_ci case 0xFF: 18808c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, "state=0x%x sense=0x%x\n", state, 18818c2ecf20Sopenharmony_ci sense); 18828c2ecf20Sopenharmony_ci skd_drive_disappeared(skdev); 18838c2ecf20Sopenharmony_ci skd_recover_requests(skdev); 18848c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 18858c2ecf20Sopenharmony_ci break; 18868c2ecf20Sopenharmony_ci default: 18878c2ecf20Sopenharmony_ci /* 18888c2ecf20Sopenharmony_ci * Uknown FW State. Wait for a state we recognize. 18898c2ecf20Sopenharmony_ci */ 18908c2ecf20Sopenharmony_ci break; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Driver state %s(%d)=>%s(%d)\n", 18938c2ecf20Sopenharmony_ci skd_skdev_state_to_str(prev_driver_state), prev_driver_state, 18948c2ecf20Sopenharmony_ci skd_skdev_state_to_str(skdev->state), skdev->state); 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_cistatic bool skd_recover_request(struct request *req, void *data, bool reserved) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct skd_device *const skdev = data; 19008c2ecf20Sopenharmony_ci struct skd_request_context *skreq = blk_mq_rq_to_pdu(req); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (skreq->state != SKD_REQ_STATE_BUSY) 19038c2ecf20Sopenharmony_ci return true; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci skd_log_skreq(skdev, skreq, "recover"); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* Release DMA resources for the request. */ 19088c2ecf20Sopenharmony_ci if (skreq->n_sg > 0) 19098c2ecf20Sopenharmony_ci skd_postop_sg_list(skdev, skreq); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci skreq->state = SKD_REQ_STATE_IDLE; 19128c2ecf20Sopenharmony_ci skreq->status = BLK_STS_IOERR; 19138c2ecf20Sopenharmony_ci blk_mq_complete_request(req); 19148c2ecf20Sopenharmony_ci return true; 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic void skd_recover_requests(struct skd_device *skdev) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci blk_mq_tagset_busy_iter(&skdev->tag_set, skd_recover_request, skdev); 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_cistatic void skd_isr_msg_from_dev(struct skd_device *skdev) 19238c2ecf20Sopenharmony_ci{ 19248c2ecf20Sopenharmony_ci u32 mfd; 19258c2ecf20Sopenharmony_ci u32 mtd; 19268c2ecf20Sopenharmony_ci u32 data; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci mfd = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "mfd=0x%x last_mtd=0x%x\n", mfd, 19318c2ecf20Sopenharmony_ci skdev->last_mtd); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci /* ignore any mtd that is an ack for something we didn't send */ 19348c2ecf20Sopenharmony_ci if (FIT_MXD_TYPE(mfd) != FIT_MXD_TYPE(skdev->last_mtd)) 19358c2ecf20Sopenharmony_ci return; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci switch (FIT_MXD_TYPE(mfd)) { 19388c2ecf20Sopenharmony_ci case FIT_MTD_FITFW_INIT: 19398c2ecf20Sopenharmony_ci skdev->proto_ver = FIT_PROTOCOL_MAJOR_VER(mfd); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (skdev->proto_ver != FIT_PROTOCOL_VERSION_1) { 19428c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "protocol mismatch\n"); 19438c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, " got=%d support=%d\n", 19448c2ecf20Sopenharmony_ci skdev->proto_ver, FIT_PROTOCOL_VERSION_1); 19458c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, " please upgrade driver\n"); 19468c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_PROTOCOL_MISMATCH; 19478c2ecf20Sopenharmony_ci skd_soft_reset(skdev); 19488c2ecf20Sopenharmony_ci break; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_GET_CMDQ_DEPTH, 0, 0); 19518c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19528c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19538c2ecf20Sopenharmony_ci break; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci case FIT_MTD_GET_CMDQ_DEPTH: 19568c2ecf20Sopenharmony_ci skdev->dev_max_queue_depth = FIT_MXD_DATA(mfd); 19578c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_DEPTH, 0, 19588c2ecf20Sopenharmony_ci SKD_N_COMPLETION_ENTRY); 19598c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19608c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19618c2ecf20Sopenharmony_ci break; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci case FIT_MTD_SET_COMPQ_DEPTH: 19648c2ecf20Sopenharmony_ci SKD_WRITEQ(skdev, skdev->cq_dma_address, FIT_MSG_TO_DEVICE_ARG); 19658c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_ADDR, 0, 0); 19668c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19678c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19688c2ecf20Sopenharmony_ci break; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci case FIT_MTD_SET_COMPQ_ADDR: 19718c2ecf20Sopenharmony_ci skd_reset_skcomp(skdev); 19728c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_HOST_ID, 0, skdev->devno); 19738c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19748c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19758c2ecf20Sopenharmony_ci break; 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci case FIT_MTD_CMD_LOG_HOST_ID: 19788c2ecf20Sopenharmony_ci /* hardware interface overflows in y2106 */ 19798c2ecf20Sopenharmony_ci skdev->connect_time_stamp = (u32)ktime_get_real_seconds(); 19808c2ecf20Sopenharmony_ci data = skdev->connect_time_stamp & 0xFFFF; 19818c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_TIME_STAMP_LO, 0, data); 19828c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19838c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19848c2ecf20Sopenharmony_ci break; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci case FIT_MTD_CMD_LOG_TIME_STAMP_LO: 19878c2ecf20Sopenharmony_ci skdev->drive_jiffies = FIT_MXD_DATA(mfd); 19888c2ecf20Sopenharmony_ci data = (skdev->connect_time_stamp >> 16) & 0xFFFF; 19898c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_TIME_STAMP_HI, 0, data); 19908c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19918c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19928c2ecf20Sopenharmony_ci break; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci case FIT_MTD_CMD_LOG_TIME_STAMP_HI: 19958c2ecf20Sopenharmony_ci skdev->drive_jiffies |= (FIT_MXD_DATA(mfd) << 16); 19968c2ecf20Sopenharmony_ci mtd = FIT_MXD_CONS(FIT_MTD_ARM_QUEUE, 0, 0); 19978c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 19988c2ecf20Sopenharmony_ci skdev->last_mtd = mtd; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Time sync driver=0x%x device=0x%x\n", 20018c2ecf20Sopenharmony_ci skdev->connect_time_stamp, skdev->drive_jiffies); 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci case FIT_MTD_ARM_QUEUE: 20058c2ecf20Sopenharmony_ci skdev->last_mtd = 0; 20068c2ecf20Sopenharmony_ci /* 20078c2ecf20Sopenharmony_ci * State should be, or soon will be, FIT_SR_DRIVE_ONLINE. 20088c2ecf20Sopenharmony_ci */ 20098c2ecf20Sopenharmony_ci break; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci default: 20128c2ecf20Sopenharmony_ci break; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cistatic void skd_disable_interrupts(struct skd_device *skdev) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci u32 sense; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci sense = SKD_READL(skdev, FIT_CONTROL); 20218c2ecf20Sopenharmony_ci sense &= ~FIT_CR_ENABLE_INTERRUPTS; 20228c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, sense, FIT_CONTROL); 20238c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "sense 0x%x\n", sense); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci /* Note that the 1s is written. A 1-bit means 20268c2ecf20Sopenharmony_ci * disable, a 0 means enable. 20278c2ecf20Sopenharmony_ci */ 20288c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, ~0, FIT_INT_MASK_HOST); 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic void skd_enable_interrupts(struct skd_device *skdev) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci u32 val; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* unmask interrupts first */ 20368c2ecf20Sopenharmony_ci val = FIT_ISH_FW_STATE_CHANGE + 20378c2ecf20Sopenharmony_ci FIT_ISH_COMPLETION_POSTED + FIT_ISH_MSG_FROM_DEV; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci /* Note that the compliment of mask is written. A 1-bit means 20408c2ecf20Sopenharmony_ci * disable, a 0 means enable. */ 20418c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, ~val, FIT_INT_MASK_HOST); 20428c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "interrupt mask=0x%x\n", ~val); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci val = SKD_READL(skdev, FIT_CONTROL); 20458c2ecf20Sopenharmony_ci val |= FIT_CR_ENABLE_INTERRUPTS; 20468c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "control=0x%x\n", val); 20478c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, val, FIT_CONTROL); 20488c2ecf20Sopenharmony_ci} 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci/* 20518c2ecf20Sopenharmony_ci ***************************************************************************** 20528c2ecf20Sopenharmony_ci * START, STOP, RESTART, QUIESCE, UNQUIESCE 20538c2ecf20Sopenharmony_ci ***************************************************************************** 20548c2ecf20Sopenharmony_ci */ 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic void skd_soft_reset(struct skd_device *skdev) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci u32 val; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci val = SKD_READL(skdev, FIT_CONTROL); 20618c2ecf20Sopenharmony_ci val |= (FIT_CR_SOFT_RESET); 20628c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "control=0x%x\n", val); 20638c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, val, FIT_CONTROL); 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic void skd_start_device(struct skd_device *skdev) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci unsigned long flags; 20698c2ecf20Sopenharmony_ci u32 sense; 20708c2ecf20Sopenharmony_ci u32 state; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci /* ack all ghost interrupts */ 20758c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci sense = SKD_READL(skdev, FIT_STATUS); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "initial status=0x%x\n", sense); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci state = sense & FIT_SR_DRIVE_STATE_MASK; 20828c2ecf20Sopenharmony_ci skdev->drive_state = state; 20838c2ecf20Sopenharmony_ci skdev->last_mtd = 0; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_STARTING; 20868c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_STARTING_TIMO; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci skd_enable_interrupts(skdev); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci switch (skdev->drive_state) { 20918c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_OFFLINE: 20928c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Drive offline...\n"); 20938c2ecf20Sopenharmony_ci break; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FW_BOOTING: 20968c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "FIT_SR_DRIVE_FW_BOOTING\n"); 20978c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_WAIT_BOOT; 20988c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; 20998c2ecf20Sopenharmony_ci break; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_SANITIZE: 21028c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, "Start: BUSY_SANITIZE\n"); 21038c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; 21048c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; 21058c2ecf20Sopenharmony_ci break; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_ERASE: 21088c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, "Start: BUSY_ERASE\n"); 21098c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY_ERASE; 21108c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; 21118c2ecf20Sopenharmony_ci break; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_INIT: 21148c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_ONLINE: 21158c2ecf20Sopenharmony_ci skd_soft_reset(skdev); 21168c2ecf20Sopenharmony_ci break; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY: 21198c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Drive Busy...\n"); 21208c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY; 21218c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; 21228c2ecf20Sopenharmony_ci break; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_SOFT_RESET: 21258c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "drive soft reset in prog\n"); 21268c2ecf20Sopenharmony_ci break; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FAULT: 21298c2ecf20Sopenharmony_ci /* Fault state is bad...soft reset won't do it... 21308c2ecf20Sopenharmony_ci * Hard reset, maybe, but does it work on device? 21318c2ecf20Sopenharmony_ci * For now, just fault so the system doesn't hang. 21328c2ecf20Sopenharmony_ci */ 21338c2ecf20Sopenharmony_ci skd_drive_fault(skdev); 21348c2ecf20Sopenharmony_ci /*start the queue so we can respond with error to requests */ 21358c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "starting queue\n"); 21368c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 21378c2ecf20Sopenharmony_ci skdev->gendisk_on = -1; 21388c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 21398c2ecf20Sopenharmony_ci break; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci case 0xFF: 21428c2ecf20Sopenharmony_ci /* Most likely the device isn't there or isn't responding 21438c2ecf20Sopenharmony_ci * to the BAR1 addresses. */ 21448c2ecf20Sopenharmony_ci skd_drive_disappeared(skdev); 21458c2ecf20Sopenharmony_ci /*start the queue so we can respond with error to requests */ 21468c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 21478c2ecf20Sopenharmony_ci "starting queue to error-out reqs\n"); 21488c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 21498c2ecf20Sopenharmony_ci skdev->gendisk_on = -1; 21508c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 21518c2ecf20Sopenharmony_ci break; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci default: 21548c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Start: unknown state %x\n", 21558c2ecf20Sopenharmony_ci skdev->drive_state); 21568c2ecf20Sopenharmony_ci break; 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_CONTROL); 21608c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "FIT Control Status=0x%x\n", state); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_INT_STATUS_HOST); 21638c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "Intr Status=0x%x\n", state); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_INT_MASK_HOST); 21668c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "Intr Mask=0x%x\n", state); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); 21698c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "Msg from Dev=0x%x\n", state); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_HW_VERSION); 21728c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "HW version=0x%x\n", state); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_cistatic void skd_stop_device(struct skd_device *skdev) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci unsigned long flags; 21808c2ecf20Sopenharmony_ci struct skd_special_context *skspcl = &skdev->internal_skspcl; 21818c2ecf20Sopenharmony_ci u32 dev_state; 21828c2ecf20Sopenharmony_ci int i; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (skdev->state != SKD_DRVR_STATE_ONLINE) { 21878c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s not online no sync\n", __func__); 21888c2ecf20Sopenharmony_ci goto stop_out; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci if (skspcl->req.state != SKD_REQ_STATE_IDLE) { 21928c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s no special\n", __func__); 21938c2ecf20Sopenharmony_ci goto stop_out; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_SYNCING; 21978c2ecf20Sopenharmony_ci skdev->sync_done = 0; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci wait_event_interruptible_timeout(skdev->waitq, 22048c2ecf20Sopenharmony_ci (skdev->sync_done), (10 * HZ)); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci switch (skdev->sync_done) { 22098c2ecf20Sopenharmony_ci case 0: 22108c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s no sync\n", __func__); 22118c2ecf20Sopenharmony_ci break; 22128c2ecf20Sopenharmony_ci case 1: 22138c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s sync done\n", __func__); 22148c2ecf20Sopenharmony_ci break; 22158c2ecf20Sopenharmony_ci default: 22168c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s sync error\n", __func__); 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_cistop_out: 22208c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_STOPPING; 22218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci skd_kill_timer(skdev); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 22268c2ecf20Sopenharmony_ci skd_disable_interrupts(skdev); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci /* ensure all ints on device are cleared */ 22298c2ecf20Sopenharmony_ci /* soft reset the device to unload with a clean slate */ 22308c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 22318c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_CR_SOFT_RESET, FIT_CONTROL); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci /* poll every 100ms, 1 second timeout */ 22368c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 22378c2ecf20Sopenharmony_ci dev_state = 22388c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_STATUS) & FIT_SR_DRIVE_STATE_MASK; 22398c2ecf20Sopenharmony_ci if (dev_state == FIT_SR_DRIVE_INIT) 22408c2ecf20Sopenharmony_ci break; 22418c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 22428c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(100)); 22438c2ecf20Sopenharmony_ci } 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (dev_state != FIT_SR_DRIVE_INIT) 22468c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "%s state error 0x%02x\n", __func__, 22478c2ecf20Sopenharmony_ci dev_state); 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci/* assume spinlock is held */ 22518c2ecf20Sopenharmony_cistatic void skd_restart_device(struct skd_device *skdev) 22528c2ecf20Sopenharmony_ci{ 22538c2ecf20Sopenharmony_ci u32 state; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci /* ack all ghost interrupts */ 22568c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci state = SKD_READL(skdev, FIT_STATUS); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "drive status=0x%x\n", state); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci state &= FIT_SR_DRIVE_STATE_MASK; 22638c2ecf20Sopenharmony_ci skdev->drive_state = state; 22648c2ecf20Sopenharmony_ci skdev->last_mtd = 0; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_RESTARTING; 22678c2ecf20Sopenharmony_ci skdev->timer_countdown = SKD_RESTARTING_TIMO; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci skd_soft_reset(skdev); 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci/* assume spinlock is held */ 22738c2ecf20Sopenharmony_cistatic int skd_quiesce_dev(struct skd_device *skdev) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci int rc = 0; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci switch (skdev->state) { 22788c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY: 22798c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_IMMINENT: 22808c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "stopping queue\n"); 22818c2ecf20Sopenharmony_ci blk_mq_stop_hw_queues(skdev->queue); 22828c2ecf20Sopenharmony_ci break; 22838c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_ONLINE: 22848c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STOPPING: 22858c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_SYNCING: 22868c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSING: 22878c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSED: 22888c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 22898c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 22908c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESUMING: 22918c2ecf20Sopenharmony_ci default: 22928c2ecf20Sopenharmony_ci rc = -EINVAL; 22938c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "state [%d] not implemented\n", 22948c2ecf20Sopenharmony_ci skdev->state); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci return rc; 22978c2ecf20Sopenharmony_ci} 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci/* assume spinlock is held */ 23008c2ecf20Sopenharmony_cistatic int skd_unquiesce_dev(struct skd_device *skdev) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci int prev_driver_state = skdev->state; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci skd_log_skdev(skdev, "unquiesce"); 23058c2ecf20Sopenharmony_ci if (skdev->state == SKD_DRVR_STATE_ONLINE) { 23068c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "**** device already ONLINE\n"); 23078c2ecf20Sopenharmony_ci return 0; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci if (skdev->drive_state != FIT_SR_DRIVE_ONLINE) { 23108c2ecf20Sopenharmony_ci /* 23118c2ecf20Sopenharmony_ci * If there has been an state change to other than 23128c2ecf20Sopenharmony_ci * ONLINE, we will rely on controller state change 23138c2ecf20Sopenharmony_ci * to come back online and restart the queue. 23148c2ecf20Sopenharmony_ci * The BUSY state means that driver is ready to 23158c2ecf20Sopenharmony_ci * continue normal processing but waiting for controller 23168c2ecf20Sopenharmony_ci * to become available. 23178c2ecf20Sopenharmony_ci */ 23188c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_BUSY; 23198c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "drive BUSY state\n"); 23208c2ecf20Sopenharmony_ci return 0; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci /* 23248c2ecf20Sopenharmony_ci * Drive has just come online, driver is either in startup, 23258c2ecf20Sopenharmony_ci * paused performing a task, or bust waiting for hardware. 23268c2ecf20Sopenharmony_ci */ 23278c2ecf20Sopenharmony_ci switch (skdev->state) { 23288c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSED: 23298c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY: 23308c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_IMMINENT: 23318c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_ERASE: 23328c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 23338c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 23348c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_FAULT: 23358c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_IDLE: 23368c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_LOAD: 23378c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_ONLINE; 23388c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "Driver state %s(%d)=>%s(%d)\n", 23398c2ecf20Sopenharmony_ci skd_skdev_state_to_str(prev_driver_state), 23408c2ecf20Sopenharmony_ci prev_driver_state, skd_skdev_state_to_str(skdev->state), 23418c2ecf20Sopenharmony_ci skdev->state); 23428c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 23438c2ecf20Sopenharmony_ci "**** device ONLINE...starting block queue\n"); 23448c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "starting queue\n"); 23458c2ecf20Sopenharmony_ci dev_info(&skdev->pdev->dev, "STEC s1120 ONLINE\n"); 23468c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 23478c2ecf20Sopenharmony_ci skdev->gendisk_on = 1; 23488c2ecf20Sopenharmony_ci wake_up_interruptible(&skdev->waitq); 23498c2ecf20Sopenharmony_ci break; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_DISAPPEARED: 23528c2ecf20Sopenharmony_ci default: 23538c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 23548c2ecf20Sopenharmony_ci "**** driver state %d, not implemented\n", 23558c2ecf20Sopenharmony_ci skdev->state); 23568c2ecf20Sopenharmony_ci return -EBUSY; 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci return 0; 23598c2ecf20Sopenharmony_ci} 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci/* 23628c2ecf20Sopenharmony_ci ***************************************************************************** 23638c2ecf20Sopenharmony_ci * PCIe MSI/MSI-X INTERRUPT HANDLERS 23648c2ecf20Sopenharmony_ci ***************************************************************************** 23658c2ecf20Sopenharmony_ci */ 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_cistatic irqreturn_t skd_reserved_isr(int irq, void *skd_host_data) 23688c2ecf20Sopenharmony_ci{ 23698c2ecf20Sopenharmony_ci struct skd_device *skdev = skd_host_data; 23708c2ecf20Sopenharmony_ci unsigned long flags; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 23738c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "MSIX = 0x%x\n", 23748c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 23758c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "MSIX reserved irq %d = 0x%x\n", irq, 23768c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 23778c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_INT_RESERVED_MASK, FIT_INT_STATUS_HOST); 23788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 23798c2ecf20Sopenharmony_ci return IRQ_HANDLED; 23808c2ecf20Sopenharmony_ci} 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_cistatic irqreturn_t skd_statec_isr(int irq, void *skd_host_data) 23838c2ecf20Sopenharmony_ci{ 23848c2ecf20Sopenharmony_ci struct skd_device *skdev = skd_host_data; 23858c2ecf20Sopenharmony_ci unsigned long flags; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 23888c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "MSIX = 0x%x\n", 23898c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 23908c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_ISH_FW_STATE_CHANGE, FIT_INT_STATUS_HOST); 23918c2ecf20Sopenharmony_ci skd_isr_fwstate(skdev); 23928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 23938c2ecf20Sopenharmony_ci return IRQ_HANDLED; 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_cistatic irqreturn_t skd_comp_q(int irq, void *skd_host_data) 23978c2ecf20Sopenharmony_ci{ 23988c2ecf20Sopenharmony_ci struct skd_device *skdev = skd_host_data; 23998c2ecf20Sopenharmony_ci unsigned long flags; 24008c2ecf20Sopenharmony_ci int flush_enqueued = 0; 24018c2ecf20Sopenharmony_ci int deferred; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 24048c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "MSIX = 0x%x\n", 24058c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 24068c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_ISH_COMPLETION_POSTED, FIT_INT_STATUS_HOST); 24078c2ecf20Sopenharmony_ci deferred = skd_isr_completion_posted(skdev, skd_isr_comp_limit, 24088c2ecf20Sopenharmony_ci &flush_enqueued); 24098c2ecf20Sopenharmony_ci if (flush_enqueued) 24108c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (deferred) 24138c2ecf20Sopenharmony_ci schedule_work(&skdev->completion_worker); 24148c2ecf20Sopenharmony_ci else if (!flush_enqueued) 24158c2ecf20Sopenharmony_ci schedule_work(&skdev->start_queue); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_cistatic irqreturn_t skd_msg_isr(int irq, void *skd_host_data) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci struct skd_device *skdev = skd_host_data; 24258c2ecf20Sopenharmony_ci unsigned long flags; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 24288c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "MSIX = 0x%x\n", 24298c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 24308c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_ISH_MSG_FROM_DEV, FIT_INT_STATUS_HOST); 24318c2ecf20Sopenharmony_ci skd_isr_msg_from_dev(skdev); 24328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 24338c2ecf20Sopenharmony_ci return IRQ_HANDLED; 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_cistatic irqreturn_t skd_qfull_isr(int irq, void *skd_host_data) 24378c2ecf20Sopenharmony_ci{ 24388c2ecf20Sopenharmony_ci struct skd_device *skdev = skd_host_data; 24398c2ecf20Sopenharmony_ci unsigned long flags; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 24428c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "MSIX = 0x%x\n", 24438c2ecf20Sopenharmony_ci SKD_READL(skdev, FIT_INT_STATUS_HOST)); 24448c2ecf20Sopenharmony_ci SKD_WRITEL(skdev, FIT_INT_QUEUE_FULL, FIT_INT_STATUS_HOST); 24458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 24468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 24478c2ecf20Sopenharmony_ci} 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci/* 24508c2ecf20Sopenharmony_ci ***************************************************************************** 24518c2ecf20Sopenharmony_ci * PCIe MSI/MSI-X SETUP 24528c2ecf20Sopenharmony_ci ***************************************************************************** 24538c2ecf20Sopenharmony_ci */ 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_cistruct skd_msix_entry { 24568c2ecf20Sopenharmony_ci char isr_name[30]; 24578c2ecf20Sopenharmony_ci}; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_cistruct skd_init_msix_entry { 24608c2ecf20Sopenharmony_ci const char *name; 24618c2ecf20Sopenharmony_ci irq_handler_t handler; 24628c2ecf20Sopenharmony_ci}; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci#define SKD_MAX_MSIX_COUNT 13 24658c2ecf20Sopenharmony_ci#define SKD_MIN_MSIX_COUNT 7 24668c2ecf20Sopenharmony_ci#define SKD_BASE_MSIX_IRQ 4 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_cistatic struct skd_init_msix_entry msix_entries[SKD_MAX_MSIX_COUNT] = { 24698c2ecf20Sopenharmony_ci { "(DMA 0)", skd_reserved_isr }, 24708c2ecf20Sopenharmony_ci { "(DMA 1)", skd_reserved_isr }, 24718c2ecf20Sopenharmony_ci { "(DMA 2)", skd_reserved_isr }, 24728c2ecf20Sopenharmony_ci { "(DMA 3)", skd_reserved_isr }, 24738c2ecf20Sopenharmony_ci { "(State Change)", skd_statec_isr }, 24748c2ecf20Sopenharmony_ci { "(COMPL_Q)", skd_comp_q }, 24758c2ecf20Sopenharmony_ci { "(MSG)", skd_msg_isr }, 24768c2ecf20Sopenharmony_ci { "(Reserved)", skd_reserved_isr }, 24778c2ecf20Sopenharmony_ci { "(Reserved)", skd_reserved_isr }, 24788c2ecf20Sopenharmony_ci { "(Queue Full 0)", skd_qfull_isr }, 24798c2ecf20Sopenharmony_ci { "(Queue Full 1)", skd_qfull_isr }, 24808c2ecf20Sopenharmony_ci { "(Queue Full 2)", skd_qfull_isr }, 24818c2ecf20Sopenharmony_ci { "(Queue Full 3)", skd_qfull_isr }, 24828c2ecf20Sopenharmony_ci}; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_cistatic int skd_acquire_msix(struct skd_device *skdev) 24858c2ecf20Sopenharmony_ci{ 24868c2ecf20Sopenharmony_ci int i, rc; 24878c2ecf20Sopenharmony_ci struct pci_dev *pdev = skdev->pdev; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci rc = pci_alloc_irq_vectors(pdev, SKD_MAX_MSIX_COUNT, SKD_MAX_MSIX_COUNT, 24908c2ecf20Sopenharmony_ci PCI_IRQ_MSIX); 24918c2ecf20Sopenharmony_ci if (rc < 0) { 24928c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "failed to enable MSI-X %d\n", rc); 24938c2ecf20Sopenharmony_ci goto out; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci skdev->msix_entries = kcalloc(SKD_MAX_MSIX_COUNT, 24978c2ecf20Sopenharmony_ci sizeof(struct skd_msix_entry), GFP_KERNEL); 24988c2ecf20Sopenharmony_ci if (!skdev->msix_entries) { 24998c2ecf20Sopenharmony_ci rc = -ENOMEM; 25008c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "msix table allocation error\n"); 25018c2ecf20Sopenharmony_ci goto out; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci /* Enable MSI-X vectors for the base queue */ 25058c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) { 25068c2ecf20Sopenharmony_ci struct skd_msix_entry *qentry = &skdev->msix_entries[i]; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci snprintf(qentry->isr_name, sizeof(qentry->isr_name), 25098c2ecf20Sopenharmony_ci "%s%d-msix %s", DRV_NAME, skdev->devno, 25108c2ecf20Sopenharmony_ci msix_entries[i].name); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci rc = devm_request_irq(&skdev->pdev->dev, 25138c2ecf20Sopenharmony_ci pci_irq_vector(skdev->pdev, i), 25148c2ecf20Sopenharmony_ci msix_entries[i].handler, 0, 25158c2ecf20Sopenharmony_ci qentry->isr_name, skdev); 25168c2ecf20Sopenharmony_ci if (rc) { 25178c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 25188c2ecf20Sopenharmony_ci "Unable to register(%d) MSI-X handler %d: %s\n", 25198c2ecf20Sopenharmony_ci rc, i, qentry->isr_name); 25208c2ecf20Sopenharmony_ci goto msix_out; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "%d msix irq(s) enabled\n", 25258c2ecf20Sopenharmony_ci SKD_MAX_MSIX_COUNT); 25268c2ecf20Sopenharmony_ci return 0; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_cimsix_out: 25298c2ecf20Sopenharmony_ci while (--i >= 0) 25308c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), skdev); 25318c2ecf20Sopenharmony_ciout: 25328c2ecf20Sopenharmony_ci kfree(skdev->msix_entries); 25338c2ecf20Sopenharmony_ci skdev->msix_entries = NULL; 25348c2ecf20Sopenharmony_ci return rc; 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cistatic int skd_acquire_irq(struct skd_device *skdev) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci struct pci_dev *pdev = skdev->pdev; 25408c2ecf20Sopenharmony_ci unsigned int irq_flag = PCI_IRQ_LEGACY; 25418c2ecf20Sopenharmony_ci int rc; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci if (skd_isr_type == SKD_IRQ_MSIX) { 25448c2ecf20Sopenharmony_ci rc = skd_acquire_msix(skdev); 25458c2ecf20Sopenharmony_ci if (!rc) 25468c2ecf20Sopenharmony_ci return 0; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 25498c2ecf20Sopenharmony_ci "failed to enable MSI-X, re-trying with MSI %d\n", rc); 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci snprintf(skdev->isr_name, sizeof(skdev->isr_name), "%s%d", DRV_NAME, 25538c2ecf20Sopenharmony_ci skdev->devno); 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (skd_isr_type != SKD_IRQ_LEGACY) 25568c2ecf20Sopenharmony_ci irq_flag |= PCI_IRQ_MSI; 25578c2ecf20Sopenharmony_ci rc = pci_alloc_irq_vectors(pdev, 1, 1, irq_flag); 25588c2ecf20Sopenharmony_ci if (rc < 0) { 25598c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, 25608c2ecf20Sopenharmony_ci "failed to allocate the MSI interrupt %d\n", rc); 25618c2ecf20Sopenharmony_ci return rc; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci rc = devm_request_irq(&pdev->dev, pdev->irq, skd_isr, 25658c2ecf20Sopenharmony_ci pdev->msi_enabled ? 0 : IRQF_SHARED, 25668c2ecf20Sopenharmony_ci skdev->isr_name, skdev); 25678c2ecf20Sopenharmony_ci if (rc) { 25688c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 25698c2ecf20Sopenharmony_ci dev_err(&skdev->pdev->dev, "failed to allocate interrupt %d\n", 25708c2ecf20Sopenharmony_ci rc); 25718c2ecf20Sopenharmony_ci return rc; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci return 0; 25758c2ecf20Sopenharmony_ci} 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_cistatic void skd_release_irq(struct skd_device *skdev) 25788c2ecf20Sopenharmony_ci{ 25798c2ecf20Sopenharmony_ci struct pci_dev *pdev = skdev->pdev; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci if (skdev->msix_entries) { 25828c2ecf20Sopenharmony_ci int i; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) { 25858c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), 25868c2ecf20Sopenharmony_ci skdev); 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci kfree(skdev->msix_entries); 25908c2ecf20Sopenharmony_ci skdev->msix_entries = NULL; 25918c2ecf20Sopenharmony_ci } else { 25928c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, pdev->irq, skdev); 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci/* 25998c2ecf20Sopenharmony_ci ***************************************************************************** 26008c2ecf20Sopenharmony_ci * CONSTRUCT 26018c2ecf20Sopenharmony_ci ***************************************************************************** 26028c2ecf20Sopenharmony_ci */ 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_cistatic void *skd_alloc_dma(struct skd_device *skdev, struct kmem_cache *s, 26058c2ecf20Sopenharmony_ci dma_addr_t *dma_handle, gfp_t gfp, 26068c2ecf20Sopenharmony_ci enum dma_data_direction dir) 26078c2ecf20Sopenharmony_ci{ 26088c2ecf20Sopenharmony_ci struct device *dev = &skdev->pdev->dev; 26098c2ecf20Sopenharmony_ci void *buf; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci buf = kmem_cache_alloc(s, gfp); 26128c2ecf20Sopenharmony_ci if (!buf) 26138c2ecf20Sopenharmony_ci return NULL; 26148c2ecf20Sopenharmony_ci *dma_handle = dma_map_single(dev, buf, 26158c2ecf20Sopenharmony_ci kmem_cache_size(s), dir); 26168c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, *dma_handle)) { 26178c2ecf20Sopenharmony_ci kmem_cache_free(s, buf); 26188c2ecf20Sopenharmony_ci buf = NULL; 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci return buf; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_cistatic void skd_free_dma(struct skd_device *skdev, struct kmem_cache *s, 26248c2ecf20Sopenharmony_ci void *vaddr, dma_addr_t dma_handle, 26258c2ecf20Sopenharmony_ci enum dma_data_direction dir) 26268c2ecf20Sopenharmony_ci{ 26278c2ecf20Sopenharmony_ci if (!vaddr) 26288c2ecf20Sopenharmony_ci return; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci dma_unmap_single(&skdev->pdev->dev, dma_handle, 26318c2ecf20Sopenharmony_ci kmem_cache_size(s), dir); 26328c2ecf20Sopenharmony_ci kmem_cache_free(s, vaddr); 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic int skd_cons_skcomp(struct skd_device *skdev) 26368c2ecf20Sopenharmony_ci{ 26378c2ecf20Sopenharmony_ci int rc = 0; 26388c2ecf20Sopenharmony_ci struct fit_completion_entry_v1 *skcomp; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 26418c2ecf20Sopenharmony_ci "comp pci_alloc, total bytes %zd entries %d\n", 26428c2ecf20Sopenharmony_ci SKD_SKCOMP_SIZE, SKD_N_COMPLETION_ENTRY); 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci skcomp = dma_alloc_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, 26458c2ecf20Sopenharmony_ci &skdev->cq_dma_address, GFP_KERNEL); 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci if (skcomp == NULL) { 26488c2ecf20Sopenharmony_ci rc = -ENOMEM; 26498c2ecf20Sopenharmony_ci goto err_out; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci skdev->skcomp_table = skcomp; 26538c2ecf20Sopenharmony_ci skdev->skerr_table = (struct fit_comp_error_info *)((char *)skcomp + 26548c2ecf20Sopenharmony_ci sizeof(*skcomp) * 26558c2ecf20Sopenharmony_ci SKD_N_COMPLETION_ENTRY); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cierr_out: 26588c2ecf20Sopenharmony_ci return rc; 26598c2ecf20Sopenharmony_ci} 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_cistatic int skd_cons_skmsg(struct skd_device *skdev) 26628c2ecf20Sopenharmony_ci{ 26638c2ecf20Sopenharmony_ci int rc = 0; 26648c2ecf20Sopenharmony_ci u32 i; 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 26678c2ecf20Sopenharmony_ci "skmsg_table kcalloc, struct %lu, count %u total %lu\n", 26688c2ecf20Sopenharmony_ci sizeof(struct skd_fitmsg_context), skdev->num_fitmsg_context, 26698c2ecf20Sopenharmony_ci sizeof(struct skd_fitmsg_context) * skdev->num_fitmsg_context); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci skdev->skmsg_table = kcalloc(skdev->num_fitmsg_context, 26728c2ecf20Sopenharmony_ci sizeof(struct skd_fitmsg_context), 26738c2ecf20Sopenharmony_ci GFP_KERNEL); 26748c2ecf20Sopenharmony_ci if (skdev->skmsg_table == NULL) { 26758c2ecf20Sopenharmony_ci rc = -ENOMEM; 26768c2ecf20Sopenharmony_ci goto err_out; 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci for (i = 0; i < skdev->num_fitmsg_context; i++) { 26808c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci skmsg = &skdev->skmsg_table[i]; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci skmsg->id = i + SKD_ID_FIT_MSG; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci skmsg->msg_buf = dma_alloc_coherent(&skdev->pdev->dev, 26878c2ecf20Sopenharmony_ci SKD_N_FITMSG_BYTES, 26888c2ecf20Sopenharmony_ci &skmsg->mb_dma_address, 26898c2ecf20Sopenharmony_ci GFP_KERNEL); 26908c2ecf20Sopenharmony_ci if (skmsg->msg_buf == NULL) { 26918c2ecf20Sopenharmony_ci rc = -ENOMEM; 26928c2ecf20Sopenharmony_ci goto err_out; 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci WARN(((uintptr_t)skmsg->msg_buf | skmsg->mb_dma_address) & 26968c2ecf20Sopenharmony_ci (FIT_QCMD_ALIGN - 1), 26978c2ecf20Sopenharmony_ci "not aligned: msg_buf %p mb_dma_address %pad\n", 26988c2ecf20Sopenharmony_ci skmsg->msg_buf, &skmsg->mb_dma_address); 26998c2ecf20Sopenharmony_ci } 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_cierr_out: 27028c2ecf20Sopenharmony_ci return rc; 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_cistatic struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, 27068c2ecf20Sopenharmony_ci u32 n_sg, 27078c2ecf20Sopenharmony_ci dma_addr_t *ret_dma_addr) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sg_list; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci sg_list = skd_alloc_dma(skdev, skdev->sglist_cache, ret_dma_addr, 27128c2ecf20Sopenharmony_ci GFP_DMA | __GFP_ZERO, DMA_TO_DEVICE); 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci if (sg_list != NULL) { 27158c2ecf20Sopenharmony_ci uint64_t dma_address = *ret_dma_addr; 27168c2ecf20Sopenharmony_ci u32 i; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci for (i = 0; i < n_sg - 1; i++) { 27198c2ecf20Sopenharmony_ci uint64_t ndp_off; 27208c2ecf20Sopenharmony_ci ndp_off = (i + 1) * sizeof(struct fit_sg_descriptor); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci sg_list[i].next_desc_ptr = dma_address + ndp_off; 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci sg_list[i].next_desc_ptr = 0LL; 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci return sg_list; 27288c2ecf20Sopenharmony_ci} 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_cistatic void skd_free_sg_list(struct skd_device *skdev, 27318c2ecf20Sopenharmony_ci struct fit_sg_descriptor *sg_list, 27328c2ecf20Sopenharmony_ci dma_addr_t dma_addr) 27338c2ecf20Sopenharmony_ci{ 27348c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!sg_list)) 27358c2ecf20Sopenharmony_ci return; 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci skd_free_dma(skdev, skdev->sglist_cache, sg_list, dma_addr, 27388c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 27398c2ecf20Sopenharmony_ci} 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_cistatic int skd_init_request(struct blk_mq_tag_set *set, struct request *rq, 27428c2ecf20Sopenharmony_ci unsigned int hctx_idx, unsigned int numa_node) 27438c2ecf20Sopenharmony_ci{ 27448c2ecf20Sopenharmony_ci struct skd_device *skdev = set->driver_data; 27458c2ecf20Sopenharmony_ci struct skd_request_context *skreq = blk_mq_rq_to_pdu(rq); 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci skreq->state = SKD_REQ_STATE_IDLE; 27488c2ecf20Sopenharmony_ci skreq->sg = (void *)(skreq + 1); 27498c2ecf20Sopenharmony_ci sg_init_table(skreq->sg, skd_sgs_per_request); 27508c2ecf20Sopenharmony_ci skreq->sksg_list = skd_cons_sg_list(skdev, skd_sgs_per_request, 27518c2ecf20Sopenharmony_ci &skreq->sksg_dma_address); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci return skreq->sksg_list ? 0 : -ENOMEM; 27548c2ecf20Sopenharmony_ci} 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_cistatic void skd_exit_request(struct blk_mq_tag_set *set, struct request *rq, 27578c2ecf20Sopenharmony_ci unsigned int hctx_idx) 27588c2ecf20Sopenharmony_ci{ 27598c2ecf20Sopenharmony_ci struct skd_device *skdev = set->driver_data; 27608c2ecf20Sopenharmony_ci struct skd_request_context *skreq = blk_mq_rq_to_pdu(rq); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci skd_free_sg_list(skdev, skreq->sksg_list, skreq->sksg_dma_address); 27638c2ecf20Sopenharmony_ci} 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_cistatic int skd_cons_sksb(struct skd_device *skdev) 27668c2ecf20Sopenharmony_ci{ 27678c2ecf20Sopenharmony_ci int rc = 0; 27688c2ecf20Sopenharmony_ci struct skd_special_context *skspcl; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci skspcl = &skdev->internal_skspcl; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci skspcl->req.id = 0 + SKD_ID_INTERNAL; 27738c2ecf20Sopenharmony_ci skspcl->req.state = SKD_REQ_STATE_IDLE; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci skspcl->data_buf = skd_alloc_dma(skdev, skdev->databuf_cache, 27768c2ecf20Sopenharmony_ci &skspcl->db_dma_address, 27778c2ecf20Sopenharmony_ci GFP_DMA | __GFP_ZERO, 27788c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 27798c2ecf20Sopenharmony_ci if (skspcl->data_buf == NULL) { 27808c2ecf20Sopenharmony_ci rc = -ENOMEM; 27818c2ecf20Sopenharmony_ci goto err_out; 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci skspcl->msg_buf = skd_alloc_dma(skdev, skdev->msgbuf_cache, 27858c2ecf20Sopenharmony_ci &skspcl->mb_dma_address, 27868c2ecf20Sopenharmony_ci GFP_DMA | __GFP_ZERO, DMA_TO_DEVICE); 27878c2ecf20Sopenharmony_ci if (skspcl->msg_buf == NULL) { 27888c2ecf20Sopenharmony_ci rc = -ENOMEM; 27898c2ecf20Sopenharmony_ci goto err_out; 27908c2ecf20Sopenharmony_ci } 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci skspcl->req.sksg_list = skd_cons_sg_list(skdev, 1, 27938c2ecf20Sopenharmony_ci &skspcl->req.sksg_dma_address); 27948c2ecf20Sopenharmony_ci if (skspcl->req.sksg_list == NULL) { 27958c2ecf20Sopenharmony_ci rc = -ENOMEM; 27968c2ecf20Sopenharmony_ci goto err_out; 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (!skd_format_internal_skspcl(skdev)) { 28008c2ecf20Sopenharmony_ci rc = -EINVAL; 28018c2ecf20Sopenharmony_ci goto err_out; 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_cierr_out: 28058c2ecf20Sopenharmony_ci return rc; 28068c2ecf20Sopenharmony_ci} 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_cistatic const struct blk_mq_ops skd_mq_ops = { 28098c2ecf20Sopenharmony_ci .queue_rq = skd_mq_queue_rq, 28108c2ecf20Sopenharmony_ci .complete = skd_complete_rq, 28118c2ecf20Sopenharmony_ci .timeout = skd_timed_out, 28128c2ecf20Sopenharmony_ci .init_request = skd_init_request, 28138c2ecf20Sopenharmony_ci .exit_request = skd_exit_request, 28148c2ecf20Sopenharmony_ci}; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_cistatic int skd_cons_disk(struct skd_device *skdev) 28178c2ecf20Sopenharmony_ci{ 28188c2ecf20Sopenharmony_ci int rc = 0; 28198c2ecf20Sopenharmony_ci struct gendisk *disk; 28208c2ecf20Sopenharmony_ci struct request_queue *q; 28218c2ecf20Sopenharmony_ci unsigned long flags; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci disk = alloc_disk(SKD_MINORS_PER_DEVICE); 28248c2ecf20Sopenharmony_ci if (!disk) { 28258c2ecf20Sopenharmony_ci rc = -ENOMEM; 28268c2ecf20Sopenharmony_ci goto err_out; 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci skdev->disk = disk; 28308c2ecf20Sopenharmony_ci sprintf(disk->disk_name, DRV_NAME "%u", skdev->devno); 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci disk->major = skdev->major; 28338c2ecf20Sopenharmony_ci disk->first_minor = skdev->devno * SKD_MINORS_PER_DEVICE; 28348c2ecf20Sopenharmony_ci disk->fops = &skd_blockdev_ops; 28358c2ecf20Sopenharmony_ci disk->private_data = skdev; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci memset(&skdev->tag_set, 0, sizeof(skdev->tag_set)); 28388c2ecf20Sopenharmony_ci skdev->tag_set.ops = &skd_mq_ops; 28398c2ecf20Sopenharmony_ci skdev->tag_set.nr_hw_queues = 1; 28408c2ecf20Sopenharmony_ci skdev->tag_set.queue_depth = skd_max_queue_depth; 28418c2ecf20Sopenharmony_ci skdev->tag_set.cmd_size = sizeof(struct skd_request_context) + 28428c2ecf20Sopenharmony_ci skdev->sgs_per_request * sizeof(struct scatterlist); 28438c2ecf20Sopenharmony_ci skdev->tag_set.numa_node = NUMA_NO_NODE; 28448c2ecf20Sopenharmony_ci skdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | 28458c2ecf20Sopenharmony_ci BLK_ALLOC_POLICY_TO_MQ_FLAG(BLK_TAG_ALLOC_FIFO); 28468c2ecf20Sopenharmony_ci skdev->tag_set.driver_data = skdev; 28478c2ecf20Sopenharmony_ci rc = blk_mq_alloc_tag_set(&skdev->tag_set); 28488c2ecf20Sopenharmony_ci if (rc) 28498c2ecf20Sopenharmony_ci goto err_out; 28508c2ecf20Sopenharmony_ci q = blk_mq_init_queue(&skdev->tag_set); 28518c2ecf20Sopenharmony_ci if (IS_ERR(q)) { 28528c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&skdev->tag_set); 28538c2ecf20Sopenharmony_ci rc = PTR_ERR(q); 28548c2ecf20Sopenharmony_ci goto err_out; 28558c2ecf20Sopenharmony_ci } 28568c2ecf20Sopenharmony_ci q->queuedata = skdev; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci skdev->queue = q; 28598c2ecf20Sopenharmony_ci disk->queue = q; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci blk_queue_write_cache(q, true, true); 28628c2ecf20Sopenharmony_ci blk_queue_max_segments(q, skdev->sgs_per_request); 28638c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(q, SKD_N_MAX_SECTORS); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci /* set optimal I/O size to 8KB */ 28668c2ecf20Sopenharmony_ci blk_queue_io_opt(q, 8192); 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NONROT, q); 28698c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci blk_queue_rq_timeout(q, 8 * HZ); 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci spin_lock_irqsave(&skdev->lock, flags); 28748c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "stopping queue\n"); 28758c2ecf20Sopenharmony_ci blk_mq_stop_hw_queues(skdev->queue); 28768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&skdev->lock, flags); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_cierr_out: 28798c2ecf20Sopenharmony_ci return rc; 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci#define SKD_N_DEV_TABLE 16u 28838c2ecf20Sopenharmony_cistatic u32 skd_next_devno; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_cistatic struct skd_device *skd_construct(struct pci_dev *pdev) 28868c2ecf20Sopenharmony_ci{ 28878c2ecf20Sopenharmony_ci struct skd_device *skdev; 28888c2ecf20Sopenharmony_ci int blk_major = skd_major; 28898c2ecf20Sopenharmony_ci size_t size; 28908c2ecf20Sopenharmony_ci int rc; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci skdev = kzalloc(sizeof(*skdev), GFP_KERNEL); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (!skdev) { 28958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "memory alloc failure\n"); 28968c2ecf20Sopenharmony_ci return NULL; 28978c2ecf20Sopenharmony_ci } 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci skdev->state = SKD_DRVR_STATE_LOAD; 29008c2ecf20Sopenharmony_ci skdev->pdev = pdev; 29018c2ecf20Sopenharmony_ci skdev->devno = skd_next_devno++; 29028c2ecf20Sopenharmony_ci skdev->major = blk_major; 29038c2ecf20Sopenharmony_ci skdev->dev_max_queue_depth = 0; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci skdev->num_req_context = skd_max_queue_depth; 29068c2ecf20Sopenharmony_ci skdev->num_fitmsg_context = skd_max_queue_depth; 29078c2ecf20Sopenharmony_ci skdev->cur_max_queue_depth = 1; 29088c2ecf20Sopenharmony_ci skdev->queue_low_water_mark = 1; 29098c2ecf20Sopenharmony_ci skdev->proto_ver = 99; 29108c2ecf20Sopenharmony_ci skdev->sgs_per_request = skd_sgs_per_request; 29118c2ecf20Sopenharmony_ci skdev->dbg_level = skd_dbg_level; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci spin_lock_init(&skdev->lock); 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci INIT_WORK(&skdev->start_queue, skd_start_queue); 29168c2ecf20Sopenharmony_ci INIT_WORK(&skdev->completion_worker, skd_completion_worker); 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci size = max(SKD_N_FITMSG_BYTES, SKD_N_SPECIAL_FITMSG_BYTES); 29198c2ecf20Sopenharmony_ci skdev->msgbuf_cache = kmem_cache_create("skd-msgbuf", size, 0, 29208c2ecf20Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 29218c2ecf20Sopenharmony_ci if (!skdev->msgbuf_cache) 29228c2ecf20Sopenharmony_ci goto err_out; 29238c2ecf20Sopenharmony_ci WARN_ONCE(kmem_cache_size(skdev->msgbuf_cache) < size, 29248c2ecf20Sopenharmony_ci "skd-msgbuf: %d < %zd\n", 29258c2ecf20Sopenharmony_ci kmem_cache_size(skdev->msgbuf_cache), size); 29268c2ecf20Sopenharmony_ci size = skd_sgs_per_request * sizeof(struct fit_sg_descriptor); 29278c2ecf20Sopenharmony_ci skdev->sglist_cache = kmem_cache_create("skd-sglist", size, 0, 29288c2ecf20Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 29298c2ecf20Sopenharmony_ci if (!skdev->sglist_cache) 29308c2ecf20Sopenharmony_ci goto err_out; 29318c2ecf20Sopenharmony_ci WARN_ONCE(kmem_cache_size(skdev->sglist_cache) < size, 29328c2ecf20Sopenharmony_ci "skd-sglist: %d < %zd\n", 29338c2ecf20Sopenharmony_ci kmem_cache_size(skdev->sglist_cache), size); 29348c2ecf20Sopenharmony_ci size = SKD_N_INTERNAL_BYTES; 29358c2ecf20Sopenharmony_ci skdev->databuf_cache = kmem_cache_create("skd-databuf", size, 0, 29368c2ecf20Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 29378c2ecf20Sopenharmony_ci if (!skdev->databuf_cache) 29388c2ecf20Sopenharmony_ci goto err_out; 29398c2ecf20Sopenharmony_ci WARN_ONCE(kmem_cache_size(skdev->databuf_cache) < size, 29408c2ecf20Sopenharmony_ci "skd-databuf: %d < %zd\n", 29418c2ecf20Sopenharmony_ci kmem_cache_size(skdev->databuf_cache), size); 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skcomp\n"); 29448c2ecf20Sopenharmony_ci rc = skd_cons_skcomp(skdev); 29458c2ecf20Sopenharmony_ci if (rc < 0) 29468c2ecf20Sopenharmony_ci goto err_out; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skmsg\n"); 29498c2ecf20Sopenharmony_ci rc = skd_cons_skmsg(skdev); 29508c2ecf20Sopenharmony_ci if (rc < 0) 29518c2ecf20Sopenharmony_ci goto err_out; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "sksb\n"); 29548c2ecf20Sopenharmony_ci rc = skd_cons_sksb(skdev); 29558c2ecf20Sopenharmony_ci if (rc < 0) 29568c2ecf20Sopenharmony_ci goto err_out; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "disk\n"); 29598c2ecf20Sopenharmony_ci rc = skd_cons_disk(skdev); 29608c2ecf20Sopenharmony_ci if (rc < 0) 29618c2ecf20Sopenharmony_ci goto err_out; 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "VICTORY\n"); 29648c2ecf20Sopenharmony_ci return skdev; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_cierr_out: 29678c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "construct failed\n"); 29688c2ecf20Sopenharmony_ci skd_destruct(skdev); 29698c2ecf20Sopenharmony_ci return NULL; 29708c2ecf20Sopenharmony_ci} 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci/* 29738c2ecf20Sopenharmony_ci ***************************************************************************** 29748c2ecf20Sopenharmony_ci * DESTRUCT (FREE) 29758c2ecf20Sopenharmony_ci ***************************************************************************** 29768c2ecf20Sopenharmony_ci */ 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_cistatic void skd_free_skcomp(struct skd_device *skdev) 29798c2ecf20Sopenharmony_ci{ 29808c2ecf20Sopenharmony_ci if (skdev->skcomp_table) 29818c2ecf20Sopenharmony_ci dma_free_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, 29828c2ecf20Sopenharmony_ci skdev->skcomp_table, skdev->cq_dma_address); 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci skdev->skcomp_table = NULL; 29858c2ecf20Sopenharmony_ci skdev->cq_dma_address = 0; 29868c2ecf20Sopenharmony_ci} 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_cistatic void skd_free_skmsg(struct skd_device *skdev) 29898c2ecf20Sopenharmony_ci{ 29908c2ecf20Sopenharmony_ci u32 i; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci if (skdev->skmsg_table == NULL) 29938c2ecf20Sopenharmony_ci return; 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci for (i = 0; i < skdev->num_fitmsg_context; i++) { 29968c2ecf20Sopenharmony_ci struct skd_fitmsg_context *skmsg; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci skmsg = &skdev->skmsg_table[i]; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci if (skmsg->msg_buf != NULL) { 30018c2ecf20Sopenharmony_ci dma_free_coherent(&skdev->pdev->dev, SKD_N_FITMSG_BYTES, 30028c2ecf20Sopenharmony_ci skmsg->msg_buf, 30038c2ecf20Sopenharmony_ci skmsg->mb_dma_address); 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci skmsg->msg_buf = NULL; 30068c2ecf20Sopenharmony_ci skmsg->mb_dma_address = 0; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci kfree(skdev->skmsg_table); 30108c2ecf20Sopenharmony_ci skdev->skmsg_table = NULL; 30118c2ecf20Sopenharmony_ci} 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_cistatic void skd_free_sksb(struct skd_device *skdev) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci struct skd_special_context *skspcl = &skdev->internal_skspcl; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci skd_free_dma(skdev, skdev->databuf_cache, skspcl->data_buf, 30188c2ecf20Sopenharmony_ci skspcl->db_dma_address, DMA_BIDIRECTIONAL); 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci skspcl->data_buf = NULL; 30218c2ecf20Sopenharmony_ci skspcl->db_dma_address = 0; 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci skd_free_dma(skdev, skdev->msgbuf_cache, skspcl->msg_buf, 30248c2ecf20Sopenharmony_ci skspcl->mb_dma_address, DMA_TO_DEVICE); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci skspcl->msg_buf = NULL; 30278c2ecf20Sopenharmony_ci skspcl->mb_dma_address = 0; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci skd_free_sg_list(skdev, skspcl->req.sksg_list, 30308c2ecf20Sopenharmony_ci skspcl->req.sksg_dma_address); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci skspcl->req.sksg_list = NULL; 30338c2ecf20Sopenharmony_ci skspcl->req.sksg_dma_address = 0; 30348c2ecf20Sopenharmony_ci} 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_cistatic void skd_free_disk(struct skd_device *skdev) 30378c2ecf20Sopenharmony_ci{ 30388c2ecf20Sopenharmony_ci struct gendisk *disk = skdev->disk; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (disk && (disk->flags & GENHD_FL_UP)) 30418c2ecf20Sopenharmony_ci del_gendisk(disk); 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci if (skdev->queue) { 30448c2ecf20Sopenharmony_ci blk_cleanup_queue(skdev->queue); 30458c2ecf20Sopenharmony_ci skdev->queue = NULL; 30468c2ecf20Sopenharmony_ci if (disk) 30478c2ecf20Sopenharmony_ci disk->queue = NULL; 30488c2ecf20Sopenharmony_ci } 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci if (skdev->tag_set.tags) 30518c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&skdev->tag_set); 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci put_disk(disk); 30548c2ecf20Sopenharmony_ci skdev->disk = NULL; 30558c2ecf20Sopenharmony_ci} 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_cistatic void skd_destruct(struct skd_device *skdev) 30588c2ecf20Sopenharmony_ci{ 30598c2ecf20Sopenharmony_ci if (skdev == NULL) 30608c2ecf20Sopenharmony_ci return; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci cancel_work_sync(&skdev->start_queue); 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "disk\n"); 30658c2ecf20Sopenharmony_ci skd_free_disk(skdev); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "sksb\n"); 30688c2ecf20Sopenharmony_ci skd_free_sksb(skdev); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skmsg\n"); 30718c2ecf20Sopenharmony_ci skd_free_skmsg(skdev); 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skcomp\n"); 30748c2ecf20Sopenharmony_ci skd_free_skcomp(skdev); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci kmem_cache_destroy(skdev->databuf_cache); 30778c2ecf20Sopenharmony_ci kmem_cache_destroy(skdev->sglist_cache); 30788c2ecf20Sopenharmony_ci kmem_cache_destroy(skdev->msgbuf_cache); 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skdev\n"); 30818c2ecf20Sopenharmony_ci kfree(skdev); 30828c2ecf20Sopenharmony_ci} 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci/* 30858c2ecf20Sopenharmony_ci ***************************************************************************** 30868c2ecf20Sopenharmony_ci * BLOCK DEVICE (BDEV) GLUE 30878c2ecf20Sopenharmony_ci ***************************************************************************** 30888c2ecf20Sopenharmony_ci */ 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cistatic int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci struct skd_device *skdev; 30938c2ecf20Sopenharmony_ci u64 capacity; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci skdev = bdev->bd_disk->private_data; 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "%s: CMD[%s] getgeo device\n", 30988c2ecf20Sopenharmony_ci bdev->bd_disk->disk_name, current->comm); 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci if (skdev->read_cap_is_valid) { 31018c2ecf20Sopenharmony_ci capacity = get_capacity(skdev->disk); 31028c2ecf20Sopenharmony_ci geo->heads = 64; 31038c2ecf20Sopenharmony_ci geo->sectors = 255; 31048c2ecf20Sopenharmony_ci geo->cylinders = (capacity) / (255 * 64); 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return 0; 31078c2ecf20Sopenharmony_ci } 31088c2ecf20Sopenharmony_ci return -EIO; 31098c2ecf20Sopenharmony_ci} 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_cistatic int skd_bdev_attach(struct device *parent, struct skd_device *skdev) 31128c2ecf20Sopenharmony_ci{ 31138c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "add_disk\n"); 31148c2ecf20Sopenharmony_ci device_add_disk(parent, skdev->disk, NULL); 31158c2ecf20Sopenharmony_ci return 0; 31168c2ecf20Sopenharmony_ci} 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_cistatic const struct block_device_operations skd_blockdev_ops = { 31198c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 31208c2ecf20Sopenharmony_ci .getgeo = skd_bdev_getgeo, 31218c2ecf20Sopenharmony_ci}; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci/* 31248c2ecf20Sopenharmony_ci ***************************************************************************** 31258c2ecf20Sopenharmony_ci * PCIe DRIVER GLUE 31268c2ecf20Sopenharmony_ci ***************************************************************************** 31278c2ecf20Sopenharmony_ci */ 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_cistatic const struct pci_device_id skd_pci_tbl[] = { 31308c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_STEC, PCI_DEVICE_ID_S1120, 31318c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 31328c2ecf20Sopenharmony_ci { 0 } /* terminate list */ 31338c2ecf20Sopenharmony_ci}; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, skd_pci_tbl); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_cistatic char *skd_pci_info(struct skd_device *skdev, char *str) 31388c2ecf20Sopenharmony_ci{ 31398c2ecf20Sopenharmony_ci int pcie_reg; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci strcpy(str, "PCIe ("); 31428c2ecf20Sopenharmony_ci pcie_reg = pci_find_capability(skdev->pdev, PCI_CAP_ID_EXP); 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci if (pcie_reg) { 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci char lwstr[6]; 31478c2ecf20Sopenharmony_ci uint16_t pcie_lstat, lspeed, lwidth; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci pcie_reg += 0x12; 31508c2ecf20Sopenharmony_ci pci_read_config_word(skdev->pdev, pcie_reg, &pcie_lstat); 31518c2ecf20Sopenharmony_ci lspeed = pcie_lstat & (0xF); 31528c2ecf20Sopenharmony_ci lwidth = (pcie_lstat & 0x3F0) >> 4; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci if (lspeed == 1) 31558c2ecf20Sopenharmony_ci strcat(str, "2.5GT/s "); 31568c2ecf20Sopenharmony_ci else if (lspeed == 2) 31578c2ecf20Sopenharmony_ci strcat(str, "5.0GT/s "); 31588c2ecf20Sopenharmony_ci else 31598c2ecf20Sopenharmony_ci strcat(str, "<unknown> "); 31608c2ecf20Sopenharmony_ci snprintf(lwstr, sizeof(lwstr), "%dX)", lwidth); 31618c2ecf20Sopenharmony_ci strcat(str, lwstr); 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci return str; 31648c2ecf20Sopenharmony_ci} 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_cistatic int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci int i; 31698c2ecf20Sopenharmony_ci int rc = 0; 31708c2ecf20Sopenharmony_ci char pci_str[32]; 31718c2ecf20Sopenharmony_ci struct skd_device *skdev; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "vendor=%04X device=%04x\n", pdev->vendor, 31748c2ecf20Sopenharmony_ci pdev->device); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 31778c2ecf20Sopenharmony_ci if (rc) 31788c2ecf20Sopenharmony_ci return rc; 31798c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 31808c2ecf20Sopenharmony_ci if (rc) 31818c2ecf20Sopenharmony_ci goto err_out; 31828c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 31838c2ecf20Sopenharmony_ci if (rc) 31848c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 31858c2ecf20Sopenharmony_ci if (rc) { 31868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA mask error %d\n", rc); 31878c2ecf20Sopenharmony_ci goto err_out_regions; 31888c2ecf20Sopenharmony_ci } 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci if (!skd_major) { 31918c2ecf20Sopenharmony_ci rc = register_blkdev(0, DRV_NAME); 31928c2ecf20Sopenharmony_ci if (rc < 0) 31938c2ecf20Sopenharmony_ci goto err_out_regions; 31948c2ecf20Sopenharmony_ci BUG_ON(!rc); 31958c2ecf20Sopenharmony_ci skd_major = rc; 31968c2ecf20Sopenharmony_ci } 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci skdev = skd_construct(pdev); 31998c2ecf20Sopenharmony_ci if (skdev == NULL) { 32008c2ecf20Sopenharmony_ci rc = -ENOMEM; 32018c2ecf20Sopenharmony_ci goto err_out_regions; 32028c2ecf20Sopenharmony_ci } 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci skd_pci_info(skdev, pci_str); 32058c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s 64bit\n", pci_str); 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci pci_set_master(pdev); 32088c2ecf20Sopenharmony_ci rc = pci_enable_pcie_error_reporting(pdev); 32098c2ecf20Sopenharmony_ci if (rc) { 32108c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 32118c2ecf20Sopenharmony_ci "bad enable of PCIe error reporting rc=%d\n", rc); 32128c2ecf20Sopenharmony_ci skdev->pcie_error_reporting_is_enabled = 0; 32138c2ecf20Sopenharmony_ci } else 32148c2ecf20Sopenharmony_ci skdev->pcie_error_reporting_is_enabled = 1; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, skdev); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) { 32198c2ecf20Sopenharmony_ci skdev->mem_phys[i] = pci_resource_start(pdev, i); 32208c2ecf20Sopenharmony_ci skdev->mem_size[i] = (u32)pci_resource_len(pdev, i); 32218c2ecf20Sopenharmony_ci skdev->mem_map[i] = ioremap(skdev->mem_phys[i], 32228c2ecf20Sopenharmony_ci skdev->mem_size[i]); 32238c2ecf20Sopenharmony_ci if (!skdev->mem_map[i]) { 32248c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 32258c2ecf20Sopenharmony_ci "Unable to map adapter memory!\n"); 32268c2ecf20Sopenharmony_ci rc = -ENODEV; 32278c2ecf20Sopenharmony_ci goto err_out_iounmap; 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "mem_map=%p, phyd=%016llx, size=%d\n", 32308c2ecf20Sopenharmony_ci skdev->mem_map[i], (uint64_t)skdev->mem_phys[i], 32318c2ecf20Sopenharmony_ci skdev->mem_size[i]); 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci rc = skd_acquire_irq(skdev); 32358c2ecf20Sopenharmony_ci if (rc) { 32368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "interrupt resource error %d\n", rc); 32378c2ecf20Sopenharmony_ci goto err_out_iounmap; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci rc = skd_start_timer(skdev); 32418c2ecf20Sopenharmony_ci if (rc) 32428c2ecf20Sopenharmony_ci goto err_out_timer; 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci init_waitqueue_head(&skdev->waitq); 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci skd_start_device(skdev); 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci rc = wait_event_interruptible_timeout(skdev->waitq, 32498c2ecf20Sopenharmony_ci (skdev->gendisk_on), 32508c2ecf20Sopenharmony_ci (SKD_START_WAIT_SECONDS * HZ)); 32518c2ecf20Sopenharmony_ci if (skdev->gendisk_on > 0) { 32528c2ecf20Sopenharmony_ci /* device came on-line after reset */ 32538c2ecf20Sopenharmony_ci skd_bdev_attach(&pdev->dev, skdev); 32548c2ecf20Sopenharmony_ci rc = 0; 32558c2ecf20Sopenharmony_ci } else { 32568c2ecf20Sopenharmony_ci /* we timed out, something is wrong with the device, 32578c2ecf20Sopenharmony_ci don't add the disk structure */ 32588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "error: waiting for s1120 timed out %d!\n", 32598c2ecf20Sopenharmony_ci rc); 32608c2ecf20Sopenharmony_ci /* in case of no error; we timeout with ENXIO */ 32618c2ecf20Sopenharmony_ci if (!rc) 32628c2ecf20Sopenharmony_ci rc = -ENXIO; 32638c2ecf20Sopenharmony_ci goto err_out_timer; 32648c2ecf20Sopenharmony_ci } 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci return rc; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_cierr_out_timer: 32698c2ecf20Sopenharmony_ci skd_stop_device(skdev); 32708c2ecf20Sopenharmony_ci skd_release_irq(skdev); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_cierr_out_iounmap: 32738c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) 32748c2ecf20Sopenharmony_ci if (skdev->mem_map[i]) 32758c2ecf20Sopenharmony_ci iounmap(skdev->mem_map[i]); 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci if (skdev->pcie_error_reporting_is_enabled) 32788c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci skd_destruct(skdev); 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_cierr_out_regions: 32838c2ecf20Sopenharmony_ci pci_release_regions(pdev); 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_cierr_out: 32868c2ecf20Sopenharmony_ci pci_disable_device(pdev); 32878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 32888c2ecf20Sopenharmony_ci return rc; 32898c2ecf20Sopenharmony_ci} 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_cistatic void skd_pci_remove(struct pci_dev *pdev) 32928c2ecf20Sopenharmony_ci{ 32938c2ecf20Sopenharmony_ci int i; 32948c2ecf20Sopenharmony_ci struct skd_device *skdev; 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci skdev = pci_get_drvdata(pdev); 32978c2ecf20Sopenharmony_ci if (!skdev) { 32988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no device data for PCI\n"); 32998c2ecf20Sopenharmony_ci return; 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci skd_stop_device(skdev); 33028c2ecf20Sopenharmony_ci skd_release_irq(skdev); 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) 33058c2ecf20Sopenharmony_ci if (skdev->mem_map[i]) 33068c2ecf20Sopenharmony_ci iounmap(skdev->mem_map[i]); 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci if (skdev->pcie_error_reporting_is_enabled) 33098c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci skd_destruct(skdev); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci pci_release_regions(pdev); 33148c2ecf20Sopenharmony_ci pci_disable_device(pdev); 33158c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci return; 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_cistatic int skd_pci_suspend(struct pci_dev *pdev, pm_message_t state) 33218c2ecf20Sopenharmony_ci{ 33228c2ecf20Sopenharmony_ci int i; 33238c2ecf20Sopenharmony_ci struct skd_device *skdev; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci skdev = pci_get_drvdata(pdev); 33268c2ecf20Sopenharmony_ci if (!skdev) { 33278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no device data for PCI\n"); 33288c2ecf20Sopenharmony_ci return -EIO; 33298c2ecf20Sopenharmony_ci } 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci skd_stop_device(skdev); 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci skd_release_irq(skdev); 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) 33368c2ecf20Sopenharmony_ci if (skdev->mem_map[i]) 33378c2ecf20Sopenharmony_ci iounmap(skdev->mem_map[i]); 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci if (skdev->pcie_error_reporting_is_enabled) 33408c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci pci_release_regions(pdev); 33438c2ecf20Sopenharmony_ci pci_save_state(pdev); 33448c2ecf20Sopenharmony_ci pci_disable_device(pdev); 33458c2ecf20Sopenharmony_ci pci_set_power_state(pdev, pci_choose_state(pdev, state)); 33468c2ecf20Sopenharmony_ci return 0; 33478c2ecf20Sopenharmony_ci} 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_cistatic int skd_pci_resume(struct pci_dev *pdev) 33508c2ecf20Sopenharmony_ci{ 33518c2ecf20Sopenharmony_ci int i; 33528c2ecf20Sopenharmony_ci int rc = 0; 33538c2ecf20Sopenharmony_ci struct skd_device *skdev; 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci skdev = pci_get_drvdata(pdev); 33568c2ecf20Sopenharmony_ci if (!skdev) { 33578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no device data for PCI\n"); 33588c2ecf20Sopenharmony_ci return -1; 33598c2ecf20Sopenharmony_ci } 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 33628c2ecf20Sopenharmony_ci pci_enable_wake(pdev, PCI_D0, 0); 33638c2ecf20Sopenharmony_ci pci_restore_state(pdev); 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 33668c2ecf20Sopenharmony_ci if (rc) 33678c2ecf20Sopenharmony_ci return rc; 33688c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 33698c2ecf20Sopenharmony_ci if (rc) 33708c2ecf20Sopenharmony_ci goto err_out; 33718c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 33728c2ecf20Sopenharmony_ci if (rc) 33738c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 33748c2ecf20Sopenharmony_ci if (rc) { 33758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA mask error %d\n", rc); 33768c2ecf20Sopenharmony_ci goto err_out_regions; 33778c2ecf20Sopenharmony_ci } 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci pci_set_master(pdev); 33808c2ecf20Sopenharmony_ci rc = pci_enable_pcie_error_reporting(pdev); 33818c2ecf20Sopenharmony_ci if (rc) { 33828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 33838c2ecf20Sopenharmony_ci "bad enable of PCIe error reporting rc=%d\n", rc); 33848c2ecf20Sopenharmony_ci skdev->pcie_error_reporting_is_enabled = 0; 33858c2ecf20Sopenharmony_ci } else 33868c2ecf20Sopenharmony_ci skdev->pcie_error_reporting_is_enabled = 1; 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) { 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci skdev->mem_phys[i] = pci_resource_start(pdev, i); 33918c2ecf20Sopenharmony_ci skdev->mem_size[i] = (u32)pci_resource_len(pdev, i); 33928c2ecf20Sopenharmony_ci skdev->mem_map[i] = ioremap(skdev->mem_phys[i], 33938c2ecf20Sopenharmony_ci skdev->mem_size[i]); 33948c2ecf20Sopenharmony_ci if (!skdev->mem_map[i]) { 33958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to map adapter memory!\n"); 33968c2ecf20Sopenharmony_ci rc = -ENODEV; 33978c2ecf20Sopenharmony_ci goto err_out_iounmap; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "mem_map=%p, phyd=%016llx, size=%d\n", 34008c2ecf20Sopenharmony_ci skdev->mem_map[i], (uint64_t)skdev->mem_phys[i], 34018c2ecf20Sopenharmony_ci skdev->mem_size[i]); 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci rc = skd_acquire_irq(skdev); 34048c2ecf20Sopenharmony_ci if (rc) { 34058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "interrupt resource error %d\n", rc); 34068c2ecf20Sopenharmony_ci goto err_out_iounmap; 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci rc = skd_start_timer(skdev); 34108c2ecf20Sopenharmony_ci if (rc) 34118c2ecf20Sopenharmony_ci goto err_out_timer; 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci init_waitqueue_head(&skdev->waitq); 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci skd_start_device(skdev); 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci return rc; 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_cierr_out_timer: 34208c2ecf20Sopenharmony_ci skd_stop_device(skdev); 34218c2ecf20Sopenharmony_ci skd_release_irq(skdev); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_cierr_out_iounmap: 34248c2ecf20Sopenharmony_ci for (i = 0; i < SKD_MAX_BARS; i++) 34258c2ecf20Sopenharmony_ci if (skdev->mem_map[i]) 34268c2ecf20Sopenharmony_ci iounmap(skdev->mem_map[i]); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci if (skdev->pcie_error_reporting_is_enabled) 34298c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_cierr_out_regions: 34328c2ecf20Sopenharmony_ci pci_release_regions(pdev); 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_cierr_out: 34358c2ecf20Sopenharmony_ci pci_disable_device(pdev); 34368c2ecf20Sopenharmony_ci return rc; 34378c2ecf20Sopenharmony_ci} 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_cistatic void skd_pci_shutdown(struct pci_dev *pdev) 34408c2ecf20Sopenharmony_ci{ 34418c2ecf20Sopenharmony_ci struct skd_device *skdev; 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s called\n", __func__); 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci skdev = pci_get_drvdata(pdev); 34468c2ecf20Sopenharmony_ci if (!skdev) { 34478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no device data for PCI\n"); 34488c2ecf20Sopenharmony_ci return; 34498c2ecf20Sopenharmony_ci } 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "calling stop\n"); 34528c2ecf20Sopenharmony_ci skd_stop_device(skdev); 34538c2ecf20Sopenharmony_ci} 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_cistatic struct pci_driver skd_driver = { 34568c2ecf20Sopenharmony_ci .name = DRV_NAME, 34578c2ecf20Sopenharmony_ci .id_table = skd_pci_tbl, 34588c2ecf20Sopenharmony_ci .probe = skd_pci_probe, 34598c2ecf20Sopenharmony_ci .remove = skd_pci_remove, 34608c2ecf20Sopenharmony_ci .suspend = skd_pci_suspend, 34618c2ecf20Sopenharmony_ci .resume = skd_pci_resume, 34628c2ecf20Sopenharmony_ci .shutdown = skd_pci_shutdown, 34638c2ecf20Sopenharmony_ci}; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci/* 34668c2ecf20Sopenharmony_ci ***************************************************************************** 34678c2ecf20Sopenharmony_ci * LOGGING SUPPORT 34688c2ecf20Sopenharmony_ci ***************************************************************************** 34698c2ecf20Sopenharmony_ci */ 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ciconst char *skd_drive_state_to_str(int state) 34728c2ecf20Sopenharmony_ci{ 34738c2ecf20Sopenharmony_ci switch (state) { 34748c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_OFFLINE: 34758c2ecf20Sopenharmony_ci return "OFFLINE"; 34768c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_INIT: 34778c2ecf20Sopenharmony_ci return "INIT"; 34788c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_ONLINE: 34798c2ecf20Sopenharmony_ci return "ONLINE"; 34808c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY: 34818c2ecf20Sopenharmony_ci return "BUSY"; 34828c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FAULT: 34838c2ecf20Sopenharmony_ci return "FAULT"; 34848c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_DEGRADED: 34858c2ecf20Sopenharmony_ci return "DEGRADED"; 34868c2ecf20Sopenharmony_ci case FIT_SR_PCIE_LINK_DOWN: 34878c2ecf20Sopenharmony_ci return "INK_DOWN"; 34888c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_SOFT_RESET: 34898c2ecf20Sopenharmony_ci return "SOFT_RESET"; 34908c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: 34918c2ecf20Sopenharmony_ci return "NEED_FW"; 34928c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_INIT_FAULT: 34938c2ecf20Sopenharmony_ci return "INIT_FAULT"; 34948c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_SANITIZE: 34958c2ecf20Sopenharmony_ci return "BUSY_SANITIZE"; 34968c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_BUSY_ERASE: 34978c2ecf20Sopenharmony_ci return "BUSY_ERASE"; 34988c2ecf20Sopenharmony_ci case FIT_SR_DRIVE_FW_BOOTING: 34998c2ecf20Sopenharmony_ci return "FW_BOOTING"; 35008c2ecf20Sopenharmony_ci default: 35018c2ecf20Sopenharmony_ci return "???"; 35028c2ecf20Sopenharmony_ci } 35038c2ecf20Sopenharmony_ci} 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ciconst char *skd_skdev_state_to_str(enum skd_drvr_state state) 35068c2ecf20Sopenharmony_ci{ 35078c2ecf20Sopenharmony_ci switch (state) { 35088c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_LOAD: 35098c2ecf20Sopenharmony_ci return "LOAD"; 35108c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_IDLE: 35118c2ecf20Sopenharmony_ci return "IDLE"; 35128c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY: 35138c2ecf20Sopenharmony_ci return "BUSY"; 35148c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STARTING: 35158c2ecf20Sopenharmony_ci return "STARTING"; 35168c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_ONLINE: 35178c2ecf20Sopenharmony_ci return "ONLINE"; 35188c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSING: 35198c2ecf20Sopenharmony_ci return "PAUSING"; 35208c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_PAUSED: 35218c2ecf20Sopenharmony_ci return "PAUSED"; 35228c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESTARTING: 35238c2ecf20Sopenharmony_ci return "RESTARTING"; 35248c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_RESUMING: 35258c2ecf20Sopenharmony_ci return "RESUMING"; 35268c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_STOPPING: 35278c2ecf20Sopenharmony_ci return "STOPPING"; 35288c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_SYNCING: 35298c2ecf20Sopenharmony_ci return "SYNCING"; 35308c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_FAULT: 35318c2ecf20Sopenharmony_ci return "FAULT"; 35328c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_DISAPPEARED: 35338c2ecf20Sopenharmony_ci return "DISAPPEARED"; 35348c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_ERASE: 35358c2ecf20Sopenharmony_ci return "BUSY_ERASE"; 35368c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_SANITIZE: 35378c2ecf20Sopenharmony_ci return "BUSY_SANITIZE"; 35388c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_BUSY_IMMINENT: 35398c2ecf20Sopenharmony_ci return "BUSY_IMMINENT"; 35408c2ecf20Sopenharmony_ci case SKD_DRVR_STATE_WAIT_BOOT: 35418c2ecf20Sopenharmony_ci return "WAIT_BOOT"; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci default: 35448c2ecf20Sopenharmony_ci return "???"; 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_cistatic const char *skd_skreq_state_to_str(enum skd_req_state state) 35498c2ecf20Sopenharmony_ci{ 35508c2ecf20Sopenharmony_ci switch (state) { 35518c2ecf20Sopenharmony_ci case SKD_REQ_STATE_IDLE: 35528c2ecf20Sopenharmony_ci return "IDLE"; 35538c2ecf20Sopenharmony_ci case SKD_REQ_STATE_SETUP: 35548c2ecf20Sopenharmony_ci return "SETUP"; 35558c2ecf20Sopenharmony_ci case SKD_REQ_STATE_BUSY: 35568c2ecf20Sopenharmony_ci return "BUSY"; 35578c2ecf20Sopenharmony_ci case SKD_REQ_STATE_COMPLETED: 35588c2ecf20Sopenharmony_ci return "COMPLETED"; 35598c2ecf20Sopenharmony_ci case SKD_REQ_STATE_TIMEOUT: 35608c2ecf20Sopenharmony_ci return "TIMEOUT"; 35618c2ecf20Sopenharmony_ci default: 35628c2ecf20Sopenharmony_ci return "???"; 35638c2ecf20Sopenharmony_ci } 35648c2ecf20Sopenharmony_ci} 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_cistatic void skd_log_skdev(struct skd_device *skdev, const char *event) 35678c2ecf20Sopenharmony_ci{ 35688c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skdev=%p event='%s'\n", skdev, event); 35698c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " drive_state=%s(%d) driver_state=%s(%d)\n", 35708c2ecf20Sopenharmony_ci skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, 35718c2ecf20Sopenharmony_ci skd_skdev_state_to_str(skdev->state), skdev->state); 35728c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " busy=%d limit=%d dev=%d lowat=%d\n", 35738c2ecf20Sopenharmony_ci skd_in_flight(skdev), skdev->cur_max_queue_depth, 35748c2ecf20Sopenharmony_ci skdev->dev_max_queue_depth, skdev->queue_low_water_mark); 35758c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " cycle=%d cycle_ix=%d\n", 35768c2ecf20Sopenharmony_ci skdev->skcomp_cycle, skdev->skcomp_ix); 35778c2ecf20Sopenharmony_ci} 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_cistatic void skd_log_skreq(struct skd_device *skdev, 35808c2ecf20Sopenharmony_ci struct skd_request_context *skreq, const char *event) 35818c2ecf20Sopenharmony_ci{ 35828c2ecf20Sopenharmony_ci struct request *req = blk_mq_rq_from_pdu(skreq); 35838c2ecf20Sopenharmony_ci u32 lba = blk_rq_pos(req); 35848c2ecf20Sopenharmony_ci u32 count = blk_rq_sectors(req); 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, "skreq=%p event='%s'\n", skreq, event); 35878c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " state=%s(%d) id=0x%04x fitmsg=0x%04x\n", 35888c2ecf20Sopenharmony_ci skd_skreq_state_to_str(skreq->state), skreq->state, skreq->id, 35898c2ecf20Sopenharmony_ci skreq->fitmsg_id); 35908c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, " sg_dir=%d n_sg=%d\n", 35918c2ecf20Sopenharmony_ci skreq->data_dir, skreq->n_sg); 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci dev_dbg(&skdev->pdev->dev, 35948c2ecf20Sopenharmony_ci "req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", req, lba, lba, 35958c2ecf20Sopenharmony_ci count, count, (int)rq_data_dir(req)); 35968c2ecf20Sopenharmony_ci} 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci/* 35998c2ecf20Sopenharmony_ci ***************************************************************************** 36008c2ecf20Sopenharmony_ci * MODULE GLUE 36018c2ecf20Sopenharmony_ci ***************************************************************************** 36028c2ecf20Sopenharmony_ci */ 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_cistatic int __init skd_init(void) 36058c2ecf20Sopenharmony_ci{ 36068c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct fit_completion_entry_v1) != 8); 36078c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct fit_comp_error_info) != 32); 36088c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct skd_command_header) != 16); 36098c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct skd_scsi_request) != 32); 36108c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct driver_inquiry_data) != 44); 36118c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct skd_msg_buf, fmh) != 0); 36128c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct skd_msg_buf, scsi) != 64); 36138c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct skd_msg_buf) != SKD_N_FITMSG_BYTES); 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci switch (skd_isr_type) { 36168c2ecf20Sopenharmony_ci case SKD_IRQ_LEGACY: 36178c2ecf20Sopenharmony_ci case SKD_IRQ_MSI: 36188c2ecf20Sopenharmony_ci case SKD_IRQ_MSIX: 36198c2ecf20Sopenharmony_ci break; 36208c2ecf20Sopenharmony_ci default: 36218c2ecf20Sopenharmony_ci pr_err(PFX "skd_isr_type %d invalid, re-set to %d\n", 36228c2ecf20Sopenharmony_ci skd_isr_type, SKD_IRQ_DEFAULT); 36238c2ecf20Sopenharmony_ci skd_isr_type = SKD_IRQ_DEFAULT; 36248c2ecf20Sopenharmony_ci } 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci if (skd_max_queue_depth < 1 || 36278c2ecf20Sopenharmony_ci skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { 36288c2ecf20Sopenharmony_ci pr_err(PFX "skd_max_queue_depth %d invalid, re-set to %d\n", 36298c2ecf20Sopenharmony_ci skd_max_queue_depth, SKD_MAX_QUEUE_DEPTH_DEFAULT); 36308c2ecf20Sopenharmony_ci skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; 36318c2ecf20Sopenharmony_ci } 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci if (skd_max_req_per_msg < 1 || 36348c2ecf20Sopenharmony_ci skd_max_req_per_msg > SKD_MAX_REQ_PER_MSG) { 36358c2ecf20Sopenharmony_ci pr_err(PFX "skd_max_req_per_msg %d invalid, re-set to %d\n", 36368c2ecf20Sopenharmony_ci skd_max_req_per_msg, SKD_MAX_REQ_PER_MSG_DEFAULT); 36378c2ecf20Sopenharmony_ci skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; 36388c2ecf20Sopenharmony_ci } 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci if (skd_sgs_per_request < 1 || skd_sgs_per_request > 4096) { 36418c2ecf20Sopenharmony_ci pr_err(PFX "skd_sg_per_request %d invalid, re-set to %d\n", 36428c2ecf20Sopenharmony_ci skd_sgs_per_request, SKD_N_SG_PER_REQ_DEFAULT); 36438c2ecf20Sopenharmony_ci skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; 36448c2ecf20Sopenharmony_ci } 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci if (skd_dbg_level < 0 || skd_dbg_level > 2) { 36478c2ecf20Sopenharmony_ci pr_err(PFX "skd_dbg_level %d invalid, re-set to %d\n", 36488c2ecf20Sopenharmony_ci skd_dbg_level, 0); 36498c2ecf20Sopenharmony_ci skd_dbg_level = 0; 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci if (skd_isr_comp_limit < 0) { 36538c2ecf20Sopenharmony_ci pr_err(PFX "skd_isr_comp_limit %d invalid, set to %d\n", 36548c2ecf20Sopenharmony_ci skd_isr_comp_limit, 0); 36558c2ecf20Sopenharmony_ci skd_isr_comp_limit = 0; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci return pci_register_driver(&skd_driver); 36598c2ecf20Sopenharmony_ci} 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_cistatic void __exit skd_exit(void) 36628c2ecf20Sopenharmony_ci{ 36638c2ecf20Sopenharmony_ci pci_unregister_driver(&skd_driver); 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci if (skd_major) 36668c2ecf20Sopenharmony_ci unregister_blkdev(skd_major, DRV_NAME); 36678c2ecf20Sopenharmony_ci} 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_cimodule_init(skd_init); 36708c2ecf20Sopenharmony_cimodule_exit(skd_exit); 3671