18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Linux MegaRAID device driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2002 LSI Logic Corporation. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2002 Red Hat, Inc. All rights reserved. 98c2ecf20Sopenharmony_ci * - fixes 108c2ecf20Sopenharmony_ci * - speed-ups (list handling fixes, issued_list, optimizations.) 118c2ecf20Sopenharmony_ci * - lots of cleanups. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (c) 2003 Christoph Hellwig <hch@lst.de> 148c2ecf20Sopenharmony_ci * - new-style, hotplug-aware pci probing and scsi registration 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju 178c2ecf20Sopenharmony_ci * <Seokmann.Ju@lsil.com> 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Description: Linux device driver for LSI Logic MegaRAID controller 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493 228c2ecf20Sopenharmony_ci * 518, 520, 531, 532 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, 258c2ecf20Sopenharmony_ci * and others. Please send updates to the mailing list 268c2ecf20Sopenharmony_ci * linux-scsi@vger.kernel.org . 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/mm.h> 308c2ecf20Sopenharmony_ci#include <linux/fs.h> 318c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 328c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 338c2ecf20Sopenharmony_ci#include <asm/io.h> 348c2ecf20Sopenharmony_ci#include <linux/completion.h> 358c2ecf20Sopenharmony_ci#include <linux/delay.h> 368c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 378c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 388c2ecf20Sopenharmony_ci#include <linux/reboot.h> 398c2ecf20Sopenharmony_ci#include <linux/module.h> 408c2ecf20Sopenharmony_ci#include <linux/list.h> 418c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 428c2ecf20Sopenharmony_ci#include <linux/pci.h> 438c2ecf20Sopenharmony_ci#include <linux/init.h> 448c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 458c2ecf20Sopenharmony_ci#include <linux/mutex.h> 468c2ecf20Sopenharmony_ci#include <linux/slab.h> 478c2ecf20Sopenharmony_ci#include <scsi/scsicam.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "scsi.h" 508c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include "megaraid.h" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define MEGARAID_MODULE_VERSION "2.00.4" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciMODULE_AUTHOR ("sju@lsil.com"); 578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver"); 588c2ecf20Sopenharmony_ciMODULE_LICENSE ("GPL"); 598c2ecf20Sopenharmony_ciMODULE_VERSION(MEGARAID_MODULE_VERSION); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(megadev_mutex); 628c2ecf20Sopenharmony_cistatic unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN; 638c2ecf20Sopenharmony_cimodule_param(max_cmd_per_lun, uint, 0); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO; 678c2ecf20Sopenharmony_cimodule_param(max_sectors_per_io, ushort, 0); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)"); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT; 728c2ecf20Sopenharmony_cimodule_param(max_mbox_busy_wait, ushort, 0); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20) 768c2ecf20Sopenharmony_ci#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C) 778c2ecf20Sopenharmony_ci#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20) 788c2ecf20Sopenharmony_ci#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Global variables 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int hba_count; 858c2ecf20Sopenharmony_cistatic adapter_t *hba_soft_state[MAX_CONTROLLERS]; 868c2ecf20Sopenharmony_cistatic struct proc_dir_entry *mega_proc_dir_entry; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* For controller re-ordering */ 898c2ecf20Sopenharmony_cistatic struct mega_hbas mega_hbas[MAX_CONTROLLERS]; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic long 928c2ecf20Sopenharmony_cimegadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * The File Operations structure for the serial/ioctl interface of the driver 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic const struct file_operations megadev_fops = { 988c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 998c2ecf20Sopenharmony_ci .unlocked_ioctl = megadev_unlocked_ioctl, 1008c2ecf20Sopenharmony_ci .open = megadev_open, 1018c2ecf20Sopenharmony_ci .llseek = noop_llseek, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * Array to structures for storing the information about the controllers. This 1068c2ecf20Sopenharmony_ci * information is sent to the user level applications, when they do an ioctl 1078c2ecf20Sopenharmony_ci * for this information. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic struct mcontroller mcontroller[MAX_CONTROLLERS]; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* The current driver version */ 1128c2ecf20Sopenharmony_cistatic u32 driver_ver = 0x02000000; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* major number used by the device for character interface */ 1158c2ecf20Sopenharmony_cistatic int major; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define IS_RAID_CH(hba, ch) (((hba)->mega_ch_class >> (ch)) & 0x01) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * Debug variable to print some diagnostic messages 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic int trace_level; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/** 1268c2ecf20Sopenharmony_ci * mega_setup_mailbox() 1278c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Allocates a 8 byte aligned memory for the handshake mailbox. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_cistatic int 1328c2ecf20Sopenharmony_cimega_setup_mailbox(adapter_t *adapter) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci unsigned long align; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci adapter->una_mbox64 = dma_alloc_coherent(&adapter->dev->dev, 1378c2ecf20Sopenharmony_ci sizeof(mbox64_t), 1388c2ecf20Sopenharmony_ci &adapter->una_mbox64_dma, 1398c2ecf20Sopenharmony_ci GFP_KERNEL); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if( !adapter->una_mbox64 ) return -1; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci adapter->mbox = &adapter->una_mbox64->mbox; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) & 1468c2ecf20Sopenharmony_ci (~0UL ^ 0xFUL)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * Register the mailbox if the controller is an io-mapped controller 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_IOMAP ) { 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci outb(adapter->mbox_dma & 0xFF, 1608c2ecf20Sopenharmony_ci adapter->host->io_port + MBOX_PORT0); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci outb((adapter->mbox_dma >> 8) & 0xFF, 1638c2ecf20Sopenharmony_ci adapter->host->io_port + MBOX_PORT1); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci outb((adapter->mbox_dma >> 16) & 0xFF, 1668c2ecf20Sopenharmony_ci adapter->host->io_port + MBOX_PORT2); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci outb((adapter->mbox_dma >> 24) & 0xFF, 1698c2ecf20Sopenharmony_ci adapter->host->io_port + MBOX_PORT3); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci outb(ENABLE_MBOX_BYTE, 1728c2ecf20Sopenharmony_ci adapter->host->io_port + ENABLE_MBOX_REGION); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci irq_ack(adapter); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci irq_enable(adapter); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * mega_query_adapter() 1858c2ecf20Sopenharmony_ci * @adapter - pointer to our soft state 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Issue the adapter inquiry commands to the controller and find out 1888c2ecf20Sopenharmony_ci * information and parameter about the devices attached 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic int 1918c2ecf20Sopenharmony_cimega_query_adapter(adapter_t *adapter) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci dma_addr_t prod_info_dma_handle; 1948c2ecf20Sopenharmony_ci mega_inquiry3 *inquiry3; 1958c2ecf20Sopenharmony_ci u8 raw_mbox[sizeof(struct mbox_out)]; 1968c2ecf20Sopenharmony_ci mbox_t *mbox; 1978c2ecf20Sopenharmony_ci int retval; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Initialize adapter inquiry mailbox */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 2048c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Try to issue Inquiry3 command 2088c2ecf20Sopenharmony_ci * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and 2098c2ecf20Sopenharmony_ci * update enquiry3 structure 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci inquiry3 = (mega_inquiry3 *)adapter->mega_buffer; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ 2168c2ecf20Sopenharmony_ci raw_mbox[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */ 2178c2ecf20Sopenharmony_ci raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Issue a blocking command to the card */ 2208c2ecf20Sopenharmony_ci if ((retval = issue_scb_block(adapter, raw_mbox))) { 2218c2ecf20Sopenharmony_ci /* the adapter does not support 40ld */ 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci mraid_ext_inquiry *ext_inq; 2248c2ecf20Sopenharmony_ci mraid_inquiry *inq; 2258c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ext_inq = dma_alloc_coherent(&adapter->dev->dev, 2288c2ecf20Sopenharmony_ci sizeof(mraid_ext_inquiry), 2298c2ecf20Sopenharmony_ci &dma_handle, GFP_KERNEL); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if( ext_inq == NULL ) return -1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci inq = &ext_inq->raid_inq; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)dma_handle; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /*issue old 0x04 command to adapter */ 2388c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci issue_scb_block(adapter, raw_mbox); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * update Enquiry3 and ProductInfo structures with 2448c2ecf20Sopenharmony_ci * mraid_inquiry structure 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci mega_8_to_40ld(inq, inquiry3, 2478c2ecf20Sopenharmony_ci (mega_product_info *)&adapter->product_info); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 2508c2ecf20Sopenharmony_ci sizeof(mraid_ext_inquiry), ext_inq, 2518c2ecf20Sopenharmony_ci dma_handle); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci } else { /*adapter supports 40ld */ 2548c2ecf20Sopenharmony_ci adapter->flag |= BOARD_40LD; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * get product_info, which is static information and will be 2588c2ecf20Sopenharmony_ci * unchanged 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci prod_info_dma_handle = dma_map_single(&adapter->dev->dev, 2618c2ecf20Sopenharmony_ci (void *)&adapter->product_info, 2628c2ecf20Sopenharmony_ci sizeof(mega_product_info), 2638c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = prod_info_dma_handle; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ 2688c2ecf20Sopenharmony_ci raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if ((retval = issue_scb_block(adapter, raw_mbox))) 2718c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 2728c2ecf20Sopenharmony_ci "Product_info cmd failed with error: %d\n", 2738c2ecf20Sopenharmony_ci retval); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, prod_info_dma_handle, 2768c2ecf20Sopenharmony_ci sizeof(mega_product_info), DMA_FROM_DEVICE); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * kernel scans the channels from 0 to <= max_channel 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci adapter->host->max_channel = 2848c2ecf20Sopenharmony_ci adapter->product_info.nchannels + NVIRT_CHAN -1; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci adapter->host->max_id = 16; /* max targets per channel */ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci adapter->host->max_lun = 7; /* Up to 7 luns for non disk devices */ 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci adapter->host->cmd_per_lun = max_cmd_per_lun; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci adapter->numldrv = inquiry3->num_ldrv; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci adapter->max_cmds = adapter->product_info.max_commands; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if(adapter->max_cmds > MAX_COMMANDS) 2978c2ecf20Sopenharmony_ci adapter->max_cmds = MAX_COMMANDS; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci adapter->host->can_queue = adapter->max_cmds - 1; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * Get the maximum number of scatter-gather elements supported by this 3038c2ecf20Sopenharmony_ci * firmware 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci mega_get_max_sgl(adapter); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci adapter->host->sg_tablesize = adapter->sglen; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* use HP firmware and bios version encoding 3108c2ecf20Sopenharmony_ci Note: fw_version[0|1] and bios_version[0|1] were originally shifted 3118c2ecf20Sopenharmony_ci right 8 bits making them zero. This 0 value was hardcoded to fix 3128c2ecf20Sopenharmony_ci sparse warnings. */ 3138c2ecf20Sopenharmony_ci if (adapter->product_info.subsysvid == PCI_VENDOR_ID_HP) { 3148c2ecf20Sopenharmony_ci snprintf(adapter->fw_version, sizeof(adapter->fw_version), 3158c2ecf20Sopenharmony_ci "%c%d%d.%d%d", 3168c2ecf20Sopenharmony_ci adapter->product_info.fw_version[2], 3178c2ecf20Sopenharmony_ci 0, 3188c2ecf20Sopenharmony_ci adapter->product_info.fw_version[1] & 0x0f, 3198c2ecf20Sopenharmony_ci 0, 3208c2ecf20Sopenharmony_ci adapter->product_info.fw_version[0] & 0x0f); 3218c2ecf20Sopenharmony_ci snprintf(adapter->bios_version, sizeof(adapter->fw_version), 3228c2ecf20Sopenharmony_ci "%c%d%d.%d%d", 3238c2ecf20Sopenharmony_ci adapter->product_info.bios_version[2], 3248c2ecf20Sopenharmony_ci 0, 3258c2ecf20Sopenharmony_ci adapter->product_info.bios_version[1] & 0x0f, 3268c2ecf20Sopenharmony_ci 0, 3278c2ecf20Sopenharmony_ci adapter->product_info.bios_version[0] & 0x0f); 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci memcpy(adapter->fw_version, 3308c2ecf20Sopenharmony_ci (char *)adapter->product_info.fw_version, 4); 3318c2ecf20Sopenharmony_ci adapter->fw_version[4] = 0; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci memcpy(adapter->bios_version, 3348c2ecf20Sopenharmony_ci (char *)adapter->product_info.bios_version, 4); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci adapter->bios_version[4] = 0; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dev_notice(&adapter->dev->dev, "[%s:%s] detected %d logical drives\n", 3408c2ecf20Sopenharmony_ci adapter->fw_version, adapter->bios_version, adapter->numldrv); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Do we support extended (>10 bytes) cdbs 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci adapter->support_ext_cdb = mega_support_ext_cdb(adapter); 3468c2ecf20Sopenharmony_ci if (adapter->support_ext_cdb) 3478c2ecf20Sopenharmony_ci dev_notice(&adapter->dev->dev, "supports extended CDBs\n"); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/** 3548c2ecf20Sopenharmony_ci * mega_runpendq() 3558c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * Runs through the list of pending requests. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_cistatic inline void 3608c2ecf20Sopenharmony_cimega_runpendq(adapter_t *adapter) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci if(!list_empty(&adapter->pending_list)) 3638c2ecf20Sopenharmony_ci __mega_runpendq(adapter); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * megaraid_queue() 3688c2ecf20Sopenharmony_ci * @scmd - Issue this scsi command 3698c2ecf20Sopenharmony_ci * @done - the callback hook into the scsi mid-layer 3708c2ecf20Sopenharmony_ci * 3718c2ecf20Sopenharmony_ci * The command queuing entry point for the mid-layer. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_cistatic int 3748c2ecf20Sopenharmony_cimegaraid_queue_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci adapter_t *adapter; 3778c2ecf20Sopenharmony_ci scb_t *scb; 3788c2ecf20Sopenharmony_ci int busy=0; 3798c2ecf20Sopenharmony_ci unsigned long flags; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci adapter = (adapter_t *)scmd->device->host->hostdata; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci scmd->scsi_done = done; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Allocate and build a SCB request 3888c2ecf20Sopenharmony_ci * busy flag will be set if mega_build_cmd() command could not 3898c2ecf20Sopenharmony_ci * allocate scb. We will return non-zero status in that case. 3908c2ecf20Sopenharmony_ci * NOTE: scb can be null even though certain commands completed 3918c2ecf20Sopenharmony_ci * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would 3928c2ecf20Sopenharmony_ci * return 0 in that case. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 3968c2ecf20Sopenharmony_ci scb = mega_build_cmd(adapter, scmd, &busy); 3978c2ecf20Sopenharmony_ci if (!scb) 3988c2ecf20Sopenharmony_ci goto out; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci scb->state |= SCB_PENDQ; 4018c2ecf20Sopenharmony_ci list_add_tail(&scb->list, &adapter->pending_list); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* 4048c2ecf20Sopenharmony_ci * Check if the HBA is in quiescent state, e.g., during a 4058c2ecf20Sopenharmony_ci * delete logical drive opertion. If it is, don't run 4068c2ecf20Sopenharmony_ci * the pending_list. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci if (atomic_read(&adapter->quiescent) == 0) 4098c2ecf20Sopenharmony_ci mega_runpendq(adapter); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci busy = 0; 4128c2ecf20Sopenharmony_ci out: 4138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 4148c2ecf20Sopenharmony_ci return busy; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(megaraid_queue) 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/** 4208c2ecf20Sopenharmony_ci * mega_allocate_scb() 4218c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 4228c2ecf20Sopenharmony_ci * @cmd: scsi command from the mid-layer 4238c2ecf20Sopenharmony_ci * 4248c2ecf20Sopenharmony_ci * Allocate a SCB structure. This is the central structure for controller 4258c2ecf20Sopenharmony_ci * commands. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_cistatic inline scb_t * 4288c2ecf20Sopenharmony_cimega_allocate_scb(adapter_t *adapter, struct scsi_cmnd *cmd) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct list_head *head = &adapter->free_list; 4318c2ecf20Sopenharmony_ci scb_t *scb; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Unlink command from Free List */ 4348c2ecf20Sopenharmony_ci if( !list_empty(head) ) { 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci scb = list_entry(head->next, scb_t, list); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci list_del_init(head->next); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci scb->state = SCB_ACTIVE; 4418c2ecf20Sopenharmony_ci scb->cmd = cmd; 4428c2ecf20Sopenharmony_ci scb->dma_type = MEGA_DMA_TYPE_NONE; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return scb; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return NULL; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/** 4518c2ecf20Sopenharmony_ci * mega_get_ldrv_num() 4528c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 4538c2ecf20Sopenharmony_ci * @cmd: scsi mid layer command 4548c2ecf20Sopenharmony_ci * @channel: channel on the controller 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * Calculate the logical drive number based on the information in scsi command 4578c2ecf20Sopenharmony_ci * and the channel number. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic inline int 4608c2ecf20Sopenharmony_cimega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci int tgt; 4638c2ecf20Sopenharmony_ci int ldrv_num; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci tgt = cmd->device->id; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if ( tgt > adapter->this_id ) 4688c2ecf20Sopenharmony_ci tgt--; /* we do not get inquires for initiator id */ 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ldrv_num = (channel * 15) + tgt; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* 4748c2ecf20Sopenharmony_ci * If we have a logical drive with boot enabled, project it first 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci if( adapter->boot_ldrv_enabled ) { 4778c2ecf20Sopenharmony_ci if( ldrv_num == 0 ) { 4788c2ecf20Sopenharmony_ci ldrv_num = adapter->boot_ldrv; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci else { 4818c2ecf20Sopenharmony_ci if( ldrv_num <= adapter->boot_ldrv ) { 4828c2ecf20Sopenharmony_ci ldrv_num--; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * If "delete logical drive" feature is enabled on this controller. 4898c2ecf20Sopenharmony_ci * Do only if at least one delete logical drive operation was done. 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci * Also, after logical drive deletion, instead of logical drive number, 4928c2ecf20Sopenharmony_ci * the value returned should be 0x80+logical drive id. 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * These is valid only for IO commands. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (adapter->support_random_del && adapter->read_ldidmap ) 4988c2ecf20Sopenharmony_ci switch (cmd->cmnd[0]) { 4998c2ecf20Sopenharmony_ci case READ_6: 5008c2ecf20Sopenharmony_ci case WRITE_6: 5018c2ecf20Sopenharmony_ci case READ_10: 5028c2ecf20Sopenharmony_ci case WRITE_10: 5038c2ecf20Sopenharmony_ci ldrv_num += 0x80; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return ldrv_num; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/** 5108c2ecf20Sopenharmony_ci * mega_build_cmd() 5118c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 5128c2ecf20Sopenharmony_ci * @cmd: Prepare using this scsi command 5138c2ecf20Sopenharmony_ci * @busy: busy flag if no resources 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * Prepares a command and scatter gather list for the controller. This routine 5168c2ecf20Sopenharmony_ci * also finds out if the commands is intended for a logical drive or a 5178c2ecf20Sopenharmony_ci * physical device and prepares the controller command accordingly. 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * We also re-order the logical drives and physical devices based on their 5208c2ecf20Sopenharmony_ci * boot settings. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_cistatic scb_t * 5238c2ecf20Sopenharmony_cimega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci mega_passthru *pthru; 5268c2ecf20Sopenharmony_ci scb_t *scb; 5278c2ecf20Sopenharmony_ci mbox_t *mbox; 5288c2ecf20Sopenharmony_ci u32 seg; 5298c2ecf20Sopenharmony_ci char islogical; 5308c2ecf20Sopenharmony_ci int max_ldrv_num; 5318c2ecf20Sopenharmony_ci int channel = 0; 5328c2ecf20Sopenharmony_ci int target = 0; 5338c2ecf20Sopenharmony_ci int ldrv_num = 0; /* logical drive number */ 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * We know what channels our logical drives are on - mega_find_card() 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci islogical = adapter->logdrv_chan[cmd->device->channel]; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* 5418c2ecf20Sopenharmony_ci * The theory: If physical drive is chosen for boot, all the physical 5428c2ecf20Sopenharmony_ci * devices are exported before the logical drives, otherwise physical 5438c2ecf20Sopenharmony_ci * devices are pushed after logical drives, in which case - Kernel sees 5448c2ecf20Sopenharmony_ci * the physical devices on virtual channel which is obviously converted 5458c2ecf20Sopenharmony_ci * to actual channel on the HBA. 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_ci if( adapter->boot_pdrv_enabled ) { 5488c2ecf20Sopenharmony_ci if( islogical ) { 5498c2ecf20Sopenharmony_ci /* logical channel */ 5508c2ecf20Sopenharmony_ci channel = cmd->device->channel - 5518c2ecf20Sopenharmony_ci adapter->product_info.nchannels; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci else { 5548c2ecf20Sopenharmony_ci /* this is physical channel */ 5558c2ecf20Sopenharmony_ci channel = cmd->device->channel; 5568c2ecf20Sopenharmony_ci target = cmd->device->id; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* 5598c2ecf20Sopenharmony_ci * boot from a physical disk, that disk needs to be 5608c2ecf20Sopenharmony_ci * exposed first IF both the channels are SCSI, then 5618c2ecf20Sopenharmony_ci * booting from the second channel is not allowed. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci if( target == 0 ) { 5648c2ecf20Sopenharmony_ci target = adapter->boot_pdrv_tgt; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci else if( target == adapter->boot_pdrv_tgt ) { 5678c2ecf20Sopenharmony_ci target = 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci else { 5728c2ecf20Sopenharmony_ci if( islogical ) { 5738c2ecf20Sopenharmony_ci /* this is the logical channel */ 5748c2ecf20Sopenharmony_ci channel = cmd->device->channel; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci else { 5778c2ecf20Sopenharmony_ci /* physical channel */ 5788c2ecf20Sopenharmony_ci channel = cmd->device->channel - NVIRT_CHAN; 5798c2ecf20Sopenharmony_ci target = cmd->device->id; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if(islogical) { 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* have just LUN 0 for each target on virtual channels */ 5878c2ecf20Sopenharmony_ci if (cmd->device->lun) { 5888c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 5898c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 5908c2ecf20Sopenharmony_ci return NULL; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci ldrv_num = mega_get_ldrv_num(adapter, cmd, channel); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci max_ldrv_num = (adapter->flag & BOARD_40LD) ? 5978c2ecf20Sopenharmony_ci MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* 6008c2ecf20Sopenharmony_ci * max_ldrv_num increases by 0x80 if some logical drive was 6018c2ecf20Sopenharmony_ci * deleted. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci if(adapter->read_ldidmap) 6048c2ecf20Sopenharmony_ci max_ldrv_num += 0x80; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if(ldrv_num > max_ldrv_num ) { 6078c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 6088c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6098c2ecf20Sopenharmony_ci return NULL; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci else { 6148c2ecf20Sopenharmony_ci if( cmd->device->lun > 7) { 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * Do not support lun >7 for physically accessed 6178c2ecf20Sopenharmony_ci * devices 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 6208c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6218c2ecf20Sopenharmony_ci return NULL; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci * Logical drive commands 6288c2ecf20Sopenharmony_ci * 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci if(islogical) { 6318c2ecf20Sopenharmony_ci switch (cmd->cmnd[0]) { 6328c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 6338c2ecf20Sopenharmony_ci#if MEGA_HAVE_CLUSTERING 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * Do we support clustering and is the support enabled 6368c2ecf20Sopenharmony_ci * If no, return success always 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci if( !adapter->has_cluster ) { 6398c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 6408c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6418c2ecf20Sopenharmony_ci return NULL; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if(!(scb = mega_allocate_scb(adapter, cmd))) { 6458c2ecf20Sopenharmony_ci *busy = 1; 6468c2ecf20Sopenharmony_ci return NULL; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci scb->raw_mbox[0] = MEGA_CLUSTER_CMD; 6508c2ecf20Sopenharmony_ci scb->raw_mbox[2] = MEGA_RESERVATION_STATUS; 6518c2ecf20Sopenharmony_ci scb->raw_mbox[3] = ldrv_num; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci scb->dma_direction = DMA_NONE; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return scb; 6568c2ecf20Sopenharmony_ci#else 6578c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 6588c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6598c2ecf20Sopenharmony_ci return NULL; 6608c2ecf20Sopenharmony_ci#endif 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci case MODE_SENSE: { 6638c2ecf20Sopenharmony_ci char *buf; 6648c2ecf20Sopenharmony_ci struct scatterlist *sg; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci sg = scsi_sglist(cmd); 6678c2ecf20Sopenharmony_ci buf = kmap_atomic(sg_page(sg)) + sg->offset; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci memset(buf, 0, cmd->cmnd[4]); 6708c2ecf20Sopenharmony_ci kunmap_atomic(buf - sg->offset); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 6738c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6748c2ecf20Sopenharmony_ci return NULL; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci case READ_CAPACITY: 6788c2ecf20Sopenharmony_ci case INQUIRY: 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if(!(adapter->flag & (1L << cmd->device->channel))) { 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci dev_notice(&adapter->dev->dev, 6838c2ecf20Sopenharmony_ci "scsi%d: scanning scsi channel %d " 6848c2ecf20Sopenharmony_ci "for logical drives\n", 6858c2ecf20Sopenharmony_ci adapter->host->host_no, 6868c2ecf20Sopenharmony_ci cmd->device->channel); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci adapter->flag |= (1L << cmd->device->channel); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Allocate a SCB and initialize passthru */ 6928c2ecf20Sopenharmony_ci if(!(scb = mega_allocate_scb(adapter, cmd))) { 6938c2ecf20Sopenharmony_ci *busy = 1; 6948c2ecf20Sopenharmony_ci return NULL; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci pthru = scb->pthru; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci mbox = (mbox_t *)scb->raw_mbox; 6998c2ecf20Sopenharmony_ci memset(mbox, 0, sizeof(scb->raw_mbox)); 7008c2ecf20Sopenharmony_ci memset(pthru, 0, sizeof(mega_passthru)); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci pthru->timeout = 0; 7038c2ecf20Sopenharmony_ci pthru->ars = 1; 7048c2ecf20Sopenharmony_ci pthru->reqsenselen = 14; 7058c2ecf20Sopenharmony_ci pthru->islogical = 1; 7068c2ecf20Sopenharmony_ci pthru->logdrv = ldrv_num; 7078c2ecf20Sopenharmony_ci pthru->cdblen = cmd->cmd_len; 7088c2ecf20Sopenharmony_ci memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if( adapter->has_64bit_addr ) { 7118c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci else { 7148c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci scb->dma_direction = DMA_FROM_DEVICE; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci pthru->numsgelements = mega_build_sglist(adapter, scb, 7208c2ecf20Sopenharmony_ci &pthru->dataxferaddr, &pthru->dataxferlen); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = scb->pthru_dma_addr; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return scb; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci case READ_6: 7278c2ecf20Sopenharmony_ci case WRITE_6: 7288c2ecf20Sopenharmony_ci case READ_10: 7298c2ecf20Sopenharmony_ci case WRITE_10: 7308c2ecf20Sopenharmony_ci case READ_12: 7318c2ecf20Sopenharmony_ci case WRITE_12: 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* Allocate a SCB and initialize mailbox */ 7348c2ecf20Sopenharmony_ci if(!(scb = mega_allocate_scb(adapter, cmd))) { 7358c2ecf20Sopenharmony_ci *busy = 1; 7368c2ecf20Sopenharmony_ci return NULL; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci mbox = (mbox_t *)scb->raw_mbox; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci memset(mbox, 0, sizeof(scb->raw_mbox)); 7418c2ecf20Sopenharmony_ci mbox->m_out.logdrv = ldrv_num; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* 7448c2ecf20Sopenharmony_ci * A little hack: 2nd bit is zero for all scsi read 7458c2ecf20Sopenharmony_ci * commands and is set for all scsi write commands 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci if( adapter->has_64bit_addr ) { 7488c2ecf20Sopenharmony_ci mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? 7498c2ecf20Sopenharmony_ci MEGA_MBOXCMD_LWRITE64: 7508c2ecf20Sopenharmony_ci MEGA_MBOXCMD_LREAD64 ; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci else { 7538c2ecf20Sopenharmony_ci mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? 7548c2ecf20Sopenharmony_ci MEGA_MBOXCMD_LWRITE: 7558c2ecf20Sopenharmony_ci MEGA_MBOXCMD_LREAD ; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* 7598c2ecf20Sopenharmony_ci * 6-byte READ(0x08) or WRITE(0x0A) cdb 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci if( cmd->cmd_len == 6 ) { 7628c2ecf20Sopenharmony_ci mbox->m_out.numsectors = (u32) cmd->cmnd[4]; 7638c2ecf20Sopenharmony_ci mbox->m_out.lba = 7648c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[1] << 16) | 7658c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[2] << 8) | 7668c2ecf20Sopenharmony_ci (u32)cmd->cmnd[3]; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci mbox->m_out.lba &= 0x1FFFFF; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 7718c2ecf20Sopenharmony_ci /* 7728c2ecf20Sopenharmony_ci * Take modulo 0x80, since the logical drive 7738c2ecf20Sopenharmony_ci * number increases by 0x80 when a logical 7748c2ecf20Sopenharmony_ci * drive was deleted 7758c2ecf20Sopenharmony_ci */ 7768c2ecf20Sopenharmony_ci if (*cmd->cmnd == READ_6) { 7778c2ecf20Sopenharmony_ci adapter->nreads[ldrv_num%0x80]++; 7788c2ecf20Sopenharmony_ci adapter->nreadblocks[ldrv_num%0x80] += 7798c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 7808c2ecf20Sopenharmony_ci } else { 7818c2ecf20Sopenharmony_ci adapter->nwrites[ldrv_num%0x80]++; 7828c2ecf20Sopenharmony_ci adapter->nwriteblocks[ldrv_num%0x80] += 7838c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci#endif 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* 7898c2ecf20Sopenharmony_ci * 10-byte READ(0x28) or WRITE(0x2A) cdb 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_ci if( cmd->cmd_len == 10 ) { 7928c2ecf20Sopenharmony_ci mbox->m_out.numsectors = 7938c2ecf20Sopenharmony_ci (u32)cmd->cmnd[8] | 7948c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[7] << 8); 7958c2ecf20Sopenharmony_ci mbox->m_out.lba = 7968c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[2] << 24) | 7978c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[3] << 16) | 7988c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[4] << 8) | 7998c2ecf20Sopenharmony_ci (u32)cmd->cmnd[5]; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 8028c2ecf20Sopenharmony_ci if (*cmd->cmnd == READ_10) { 8038c2ecf20Sopenharmony_ci adapter->nreads[ldrv_num%0x80]++; 8048c2ecf20Sopenharmony_ci adapter->nreadblocks[ldrv_num%0x80] += 8058c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 8068c2ecf20Sopenharmony_ci } else { 8078c2ecf20Sopenharmony_ci adapter->nwrites[ldrv_num%0x80]++; 8088c2ecf20Sopenharmony_ci adapter->nwriteblocks[ldrv_num%0x80] += 8098c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci#endif 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * 12-byte READ(0xA8) or WRITE(0xAA) cdb 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci if( cmd->cmd_len == 12 ) { 8188c2ecf20Sopenharmony_ci mbox->m_out.lba = 8198c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[2] << 24) | 8208c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[3] << 16) | 8218c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[4] << 8) | 8228c2ecf20Sopenharmony_ci (u32)cmd->cmnd[5]; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci mbox->m_out.numsectors = 8258c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[6] << 24) | 8268c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[7] << 16) | 8278c2ecf20Sopenharmony_ci ((u32)cmd->cmnd[8] << 8) | 8288c2ecf20Sopenharmony_ci (u32)cmd->cmnd[9]; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 8318c2ecf20Sopenharmony_ci if (*cmd->cmnd == READ_12) { 8328c2ecf20Sopenharmony_ci adapter->nreads[ldrv_num%0x80]++; 8338c2ecf20Sopenharmony_ci adapter->nreadblocks[ldrv_num%0x80] += 8348c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci adapter->nwrites[ldrv_num%0x80]++; 8378c2ecf20Sopenharmony_ci adapter->nwriteblocks[ldrv_num%0x80] += 8388c2ecf20Sopenharmony_ci mbox->m_out.numsectors; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci#endif 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * If it is a read command 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci if( (*cmd->cmnd & 0x0F) == 0x08 ) { 8478c2ecf20Sopenharmony_ci scb->dma_direction = DMA_FROM_DEVICE; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci else { 8508c2ecf20Sopenharmony_ci scb->dma_direction = DMA_TO_DEVICE; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* Calculate Scatter-Gather info */ 8548c2ecf20Sopenharmony_ci mbox->m_out.numsgelements = mega_build_sglist(adapter, scb, 8558c2ecf20Sopenharmony_ci (u32 *)&mbox->m_out.xferaddr, &seg); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return scb; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci#if MEGA_HAVE_CLUSTERING 8608c2ecf20Sopenharmony_ci case RESERVE: 8618c2ecf20Sopenharmony_ci case RELEASE: 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * Do we support clustering and is the support enabled 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci if( ! adapter->has_cluster ) { 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 8698c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 8708c2ecf20Sopenharmony_ci return NULL; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* Allocate a SCB and initialize mailbox */ 8748c2ecf20Sopenharmony_ci if(!(scb = mega_allocate_scb(adapter, cmd))) { 8758c2ecf20Sopenharmony_ci *busy = 1; 8768c2ecf20Sopenharmony_ci return NULL; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci scb->raw_mbox[0] = MEGA_CLUSTER_CMD; 8808c2ecf20Sopenharmony_ci scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ? 8818c2ecf20Sopenharmony_ci MEGA_RESERVE_LD : MEGA_RELEASE_LD; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci scb->raw_mbox[3] = ldrv_num; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci scb->dma_direction = DMA_NONE; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return scb; 8888c2ecf20Sopenharmony_ci#endif 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci default: 8918c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 8928c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 8938c2ecf20Sopenharmony_ci return NULL; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* 8988c2ecf20Sopenharmony_ci * Passthru drive commands 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci else { 9018c2ecf20Sopenharmony_ci /* Allocate a SCB and initialize passthru */ 9028c2ecf20Sopenharmony_ci if(!(scb = mega_allocate_scb(adapter, cmd))) { 9038c2ecf20Sopenharmony_ci *busy = 1; 9048c2ecf20Sopenharmony_ci return NULL; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci mbox = (mbox_t *)scb->raw_mbox; 9088c2ecf20Sopenharmony_ci memset(mbox, 0, sizeof(scb->raw_mbox)); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if( adapter->support_ext_cdb ) { 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci mega_prepare_extpassthru(adapter, scb, cmd, 9138c2ecf20Sopenharmony_ci channel, target); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = scb->epthru_dma_addr; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci else { 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci pthru = mega_prepare_passthru(adapter, scb, cmd, 9238c2ecf20Sopenharmony_ci channel, target); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Initialize mailbox */ 9268c2ecf20Sopenharmony_ci if( adapter->has_64bit_addr ) { 9278c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci else { 9308c2ecf20Sopenharmony_ci mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = scb->pthru_dma_addr; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci return scb; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci return NULL; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/** 9438c2ecf20Sopenharmony_ci * mega_prepare_passthru() 9448c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 9458c2ecf20Sopenharmony_ci * @scb: our scsi control block 9468c2ecf20Sopenharmony_ci * @cmd: scsi command from the mid-layer 9478c2ecf20Sopenharmony_ci * @channel: actual channel on the controller 9488c2ecf20Sopenharmony_ci * @target: actual id on the controller. 9498c2ecf20Sopenharmony_ci * 9508c2ecf20Sopenharmony_ci * prepare a command for the scsi physical devices. 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_cistatic mega_passthru * 9538c2ecf20Sopenharmony_cimega_prepare_passthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *cmd, 9548c2ecf20Sopenharmony_ci int channel, int target) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci mega_passthru *pthru; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci pthru = scb->pthru; 9598c2ecf20Sopenharmony_ci memset(pthru, 0, sizeof (mega_passthru)); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* 0=6sec/1=60sec/2=10min/3=3hrs */ 9628c2ecf20Sopenharmony_ci pthru->timeout = 2; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci pthru->ars = 1; 9658c2ecf20Sopenharmony_ci pthru->reqsenselen = 14; 9668c2ecf20Sopenharmony_ci pthru->islogical = 0; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci pthru->target = (adapter->flag & BOARD_40LD) ? 9718c2ecf20Sopenharmony_ci (channel << 4) | target : target; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci pthru->cdblen = cmd->cmd_len; 9748c2ecf20Sopenharmony_ci pthru->logdrv = cmd->device->lun; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* Not sure about the direction */ 9798c2ecf20Sopenharmony_ci scb->dma_direction = DMA_BIDIRECTIONAL; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ 9828c2ecf20Sopenharmony_ci switch (cmd->cmnd[0]) { 9838c2ecf20Sopenharmony_ci case INQUIRY: 9848c2ecf20Sopenharmony_ci case READ_CAPACITY: 9858c2ecf20Sopenharmony_ci if(!(adapter->flag & (1L << cmd->device->channel))) { 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci dev_notice(&adapter->dev->dev, 9888c2ecf20Sopenharmony_ci "scsi%d: scanning scsi channel %d [P%d] " 9898c2ecf20Sopenharmony_ci "for physical devices\n", 9908c2ecf20Sopenharmony_ci adapter->host->host_no, 9918c2ecf20Sopenharmony_ci cmd->device->channel, channel); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci adapter->flag |= (1L << cmd->device->channel); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci fallthrough; 9968c2ecf20Sopenharmony_ci default: 9978c2ecf20Sopenharmony_ci pthru->numsgelements = mega_build_sglist(adapter, scb, 9988c2ecf20Sopenharmony_ci &pthru->dataxferaddr, &pthru->dataxferlen); 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci return pthru; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/** 10068c2ecf20Sopenharmony_ci * mega_prepare_extpassthru() 10078c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 10088c2ecf20Sopenharmony_ci * @scb: our scsi control block 10098c2ecf20Sopenharmony_ci * @cmd: scsi command from the mid-layer 10108c2ecf20Sopenharmony_ci * @channel: actual channel on the controller 10118c2ecf20Sopenharmony_ci * @target: actual id on the controller. 10128c2ecf20Sopenharmony_ci * 10138c2ecf20Sopenharmony_ci * prepare a command for the scsi physical devices. This rountine prepares 10148c2ecf20Sopenharmony_ci * commands for devices which can take extended CDBs (>10 bytes) 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_cistatic mega_ext_passthru * 10178c2ecf20Sopenharmony_cimega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, 10188c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd, 10198c2ecf20Sopenharmony_ci int channel, int target) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci mega_ext_passthru *epthru; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci epthru = scb->epthru; 10248c2ecf20Sopenharmony_ci memset(epthru, 0, sizeof(mega_ext_passthru)); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* 0=6sec/1=60sec/2=10min/3=3hrs */ 10278c2ecf20Sopenharmony_ci epthru->timeout = 2; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci epthru->ars = 1; 10308c2ecf20Sopenharmony_ci epthru->reqsenselen = 14; 10318c2ecf20Sopenharmony_ci epthru->islogical = 0; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci epthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; 10348c2ecf20Sopenharmony_ci epthru->target = (adapter->flag & BOARD_40LD) ? 10358c2ecf20Sopenharmony_ci (channel << 4) | target : target; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci epthru->cdblen = cmd->cmd_len; 10388c2ecf20Sopenharmony_ci epthru->logdrv = cmd->device->lun; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci memcpy(epthru->cdb, cmd->cmnd, cmd->cmd_len); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* Not sure about the direction */ 10438c2ecf20Sopenharmony_ci scb->dma_direction = DMA_BIDIRECTIONAL; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci switch(cmd->cmnd[0]) { 10468c2ecf20Sopenharmony_ci case INQUIRY: 10478c2ecf20Sopenharmony_ci case READ_CAPACITY: 10488c2ecf20Sopenharmony_ci if(!(adapter->flag & (1L << cmd->device->channel))) { 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci dev_notice(&adapter->dev->dev, 10518c2ecf20Sopenharmony_ci "scsi%d: scanning scsi channel %d [P%d] " 10528c2ecf20Sopenharmony_ci "for physical devices\n", 10538c2ecf20Sopenharmony_ci adapter->host->host_no, 10548c2ecf20Sopenharmony_ci cmd->device->channel, channel); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci adapter->flag |= (1L << cmd->device->channel); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci fallthrough; 10598c2ecf20Sopenharmony_ci default: 10608c2ecf20Sopenharmony_ci epthru->numsgelements = mega_build_sglist(adapter, scb, 10618c2ecf20Sopenharmony_ci &epthru->dataxferaddr, &epthru->dataxferlen); 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci return epthru; 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic void 10698c2ecf20Sopenharmony_ci__mega_runpendq(adapter_t *adapter) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci scb_t *scb; 10728c2ecf20Sopenharmony_ci struct list_head *pos, *next; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* Issue any pending commands to the card */ 10758c2ecf20Sopenharmony_ci list_for_each_safe(pos, next, &adapter->pending_list) { 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci scb = list_entry(pos, scb_t, list); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if( !(scb->state & SCB_ISSUED) ) { 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if( issue_scb(adapter, scb) != 0 ) 10828c2ecf20Sopenharmony_ci return; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci return; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci/** 10918c2ecf20Sopenharmony_ci * issue_scb() 10928c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 10938c2ecf20Sopenharmony_ci * @scb: scsi control block 10948c2ecf20Sopenharmony_ci * 10958c2ecf20Sopenharmony_ci * Post a command to the card if the mailbox is available, otherwise return 10968c2ecf20Sopenharmony_ci * busy. We also take the scb from the pending list if the mailbox is 10978c2ecf20Sopenharmony_ci * available. 10988c2ecf20Sopenharmony_ci */ 10998c2ecf20Sopenharmony_cistatic int 11008c2ecf20Sopenharmony_ciissue_scb(adapter_t *adapter, scb_t *scb) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci volatile mbox64_t *mbox64 = adapter->mbox64; 11038c2ecf20Sopenharmony_ci volatile mbox_t *mbox = adapter->mbox; 11048c2ecf20Sopenharmony_ci unsigned int i = 0; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if(unlikely(mbox->m_in.busy)) { 11078c2ecf20Sopenharmony_ci do { 11088c2ecf20Sopenharmony_ci udelay(1); 11098c2ecf20Sopenharmony_ci i++; 11108c2ecf20Sopenharmony_ci } while( mbox->m_in.busy && (i < max_mbox_busy_wait) ); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if(mbox->m_in.busy) return -1; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* Copy mailbox data into host structure */ 11168c2ecf20Sopenharmony_ci memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, 11178c2ecf20Sopenharmony_ci sizeof(struct mbox_out)); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci mbox->m_out.cmdid = scb->idx; /* Set cmdid */ 11208c2ecf20Sopenharmony_ci mbox->m_in.busy = 1; /* Set busy */ 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* 11248c2ecf20Sopenharmony_ci * Increment the pending queue counter 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci atomic_inc(&adapter->pend_cmds); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci switch (mbox->m_out.cmd) { 11298c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_LREAD64: 11308c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_LWRITE64: 11318c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_PASSTHRU64: 11328c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_EXTPTHRU: 11338c2ecf20Sopenharmony_ci mbox64->xfer_segment_lo = mbox->m_out.xferaddr; 11348c2ecf20Sopenharmony_ci mbox64->xfer_segment_hi = 0; 11358c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = 0xFFFFFFFF; 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci default: 11388c2ecf20Sopenharmony_ci mbox64->xfer_segment_lo = 0; 11398c2ecf20Sopenharmony_ci mbox64->xfer_segment_hi = 0; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * post the command 11448c2ecf20Sopenharmony_ci */ 11458c2ecf20Sopenharmony_ci scb->state |= SCB_ISSUED; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if( likely(adapter->flag & BOARD_MEMMAP) ) { 11488c2ecf20Sopenharmony_ci mbox->m_in.poll = 0; 11498c2ecf20Sopenharmony_ci mbox->m_in.ack = 0; 11508c2ecf20Sopenharmony_ci WRINDOOR(adapter, adapter->mbox_dma | 0x1); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci else { 11538c2ecf20Sopenharmony_ci irq_enable(adapter); 11548c2ecf20Sopenharmony_ci issue_command(adapter); 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return 0; 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci/* 11618c2ecf20Sopenharmony_ci * Wait until the controller's mailbox is available 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_cistatic inline int 11648c2ecf20Sopenharmony_cimega_busywait_mbox (adapter_t *adapter) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci if (adapter->mbox->m_in.busy) 11678c2ecf20Sopenharmony_ci return __mega_busywait_mbox(adapter); 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/** 11728c2ecf20Sopenharmony_ci * issue_scb_block() 11738c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 11748c2ecf20Sopenharmony_ci * @raw_mbox: the mailbox 11758c2ecf20Sopenharmony_ci * 11768c2ecf20Sopenharmony_ci * Issue a scb in synchronous and non-interrupt mode 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_cistatic int 11798c2ecf20Sopenharmony_ciissue_scb_block(adapter_t *adapter, u_char *raw_mbox) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci volatile mbox64_t *mbox64 = adapter->mbox64; 11828c2ecf20Sopenharmony_ci volatile mbox_t *mbox = adapter->mbox; 11838c2ecf20Sopenharmony_ci u8 byte; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* Wait until mailbox is free */ 11868c2ecf20Sopenharmony_ci if(mega_busywait_mbox (adapter)) 11878c2ecf20Sopenharmony_ci goto bug_blocked_mailbox; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* Copy mailbox data into host structure */ 11908c2ecf20Sopenharmony_ci memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out)); 11918c2ecf20Sopenharmony_ci mbox->m_out.cmdid = 0xFE; 11928c2ecf20Sopenharmony_ci mbox->m_in.busy = 1; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci switch (raw_mbox[0]) { 11958c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_LREAD64: 11968c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_LWRITE64: 11978c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_PASSTHRU64: 11988c2ecf20Sopenharmony_ci case MEGA_MBOXCMD_EXTPTHRU: 11998c2ecf20Sopenharmony_ci mbox64->xfer_segment_lo = mbox->m_out.xferaddr; 12008c2ecf20Sopenharmony_ci mbox64->xfer_segment_hi = 0; 12018c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = 0xFFFFFFFF; 12028c2ecf20Sopenharmony_ci break; 12038c2ecf20Sopenharmony_ci default: 12048c2ecf20Sopenharmony_ci mbox64->xfer_segment_lo = 0; 12058c2ecf20Sopenharmony_ci mbox64->xfer_segment_hi = 0; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if( likely(adapter->flag & BOARD_MEMMAP) ) { 12098c2ecf20Sopenharmony_ci mbox->m_in.poll = 0; 12108c2ecf20Sopenharmony_ci mbox->m_in.ack = 0; 12118c2ecf20Sopenharmony_ci mbox->m_in.numstatus = 0xFF; 12128c2ecf20Sopenharmony_ci mbox->m_in.status = 0xFF; 12138c2ecf20Sopenharmony_ci WRINDOOR(adapter, adapter->mbox_dma | 0x1); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci while((volatile u8)mbox->m_in.numstatus == 0xFF) 12168c2ecf20Sopenharmony_ci cpu_relax(); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci mbox->m_in.numstatus = 0xFF; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci while( (volatile u8)mbox->m_in.poll != 0x77 ) 12218c2ecf20Sopenharmony_ci cpu_relax(); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci mbox->m_in.poll = 0; 12248c2ecf20Sopenharmony_ci mbox->m_in.ack = 0x77; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci WRINDOOR(adapter, adapter->mbox_dma | 0x2); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci while(RDINDOOR(adapter) & 0x2) 12298c2ecf20Sopenharmony_ci cpu_relax(); 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci else { 12328c2ecf20Sopenharmony_ci irq_disable(adapter); 12338c2ecf20Sopenharmony_ci issue_command(adapter); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci while (!((byte = irq_state(adapter)) & INTR_VALID)) 12368c2ecf20Sopenharmony_ci cpu_relax(); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci set_irq_state(adapter, byte); 12398c2ecf20Sopenharmony_ci irq_enable(adapter); 12408c2ecf20Sopenharmony_ci irq_ack(adapter); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci return mbox->m_in.status; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cibug_blocked_mailbox: 12468c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "Blocked mailbox......!!\n"); 12478c2ecf20Sopenharmony_ci udelay (1000); 12488c2ecf20Sopenharmony_ci return -1; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci/** 12538c2ecf20Sopenharmony_ci * megaraid_isr_iomapped() 12548c2ecf20Sopenharmony_ci * @irq: irq 12558c2ecf20Sopenharmony_ci * @devp: pointer to our soft state 12568c2ecf20Sopenharmony_ci * 12578c2ecf20Sopenharmony_ci * Interrupt service routine for io-mapped controllers. 12588c2ecf20Sopenharmony_ci * Find out if our device is interrupting. If yes, acknowledge the interrupt 12598c2ecf20Sopenharmony_ci * and service the completed commands. 12608c2ecf20Sopenharmony_ci */ 12618c2ecf20Sopenharmony_cistatic irqreturn_t 12628c2ecf20Sopenharmony_cimegaraid_isr_iomapped(int irq, void *devp) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci adapter_t *adapter = devp; 12658c2ecf20Sopenharmony_ci unsigned long flags; 12668c2ecf20Sopenharmony_ci u8 status; 12678c2ecf20Sopenharmony_ci u8 nstatus; 12688c2ecf20Sopenharmony_ci u8 completed[MAX_FIRMWARE_STATUS]; 12698c2ecf20Sopenharmony_ci u8 byte; 12708c2ecf20Sopenharmony_ci int handled = 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * loop till F/W has more commands for us to complete. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci do { 12798c2ecf20Sopenharmony_ci /* Check if a valid interrupt is pending */ 12808c2ecf20Sopenharmony_ci byte = irq_state(adapter); 12818c2ecf20Sopenharmony_ci if( (byte & VALID_INTR_BYTE) == 0 ) { 12828c2ecf20Sopenharmony_ci /* 12838c2ecf20Sopenharmony_ci * No more pending commands 12848c2ecf20Sopenharmony_ci */ 12858c2ecf20Sopenharmony_ci goto out_unlock; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci set_irq_state(adapter, byte); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) 12908c2ecf20Sopenharmony_ci == 0xFF) 12918c2ecf20Sopenharmony_ci cpu_relax(); 12928c2ecf20Sopenharmony_ci adapter->mbox->m_in.numstatus = 0xFF; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci status = adapter->mbox->m_in.status; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * decrement the pending queue counter 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ci atomic_sub(nstatus, &adapter->pend_cmds); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci memcpy(completed, (void *)adapter->mbox->m_in.completed, 13028c2ecf20Sopenharmony_ci nstatus); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* Acknowledge interrupt */ 13058c2ecf20Sopenharmony_ci irq_ack(adapter); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci mega_cmd_done(adapter, completed, nstatus, status); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci mega_rundoneq(adapter); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci handled = 1; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* Loop through any pending requests */ 13148c2ecf20Sopenharmony_ci if(atomic_read(&adapter->quiescent) == 0) { 13158c2ecf20Sopenharmony_ci mega_runpendq(adapter); 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci } while(1); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci out_unlock: 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci/** 13298c2ecf20Sopenharmony_ci * megaraid_isr_memmapped() 13308c2ecf20Sopenharmony_ci * @irq: irq 13318c2ecf20Sopenharmony_ci * @devp: pointer to our soft state 13328c2ecf20Sopenharmony_ci * 13338c2ecf20Sopenharmony_ci * Interrupt service routine for memory-mapped controllers. 13348c2ecf20Sopenharmony_ci * Find out if our device is interrupting. If yes, acknowledge the interrupt 13358c2ecf20Sopenharmony_ci * and service the completed commands. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_cistatic irqreturn_t 13388c2ecf20Sopenharmony_cimegaraid_isr_memmapped(int irq, void *devp) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci adapter_t *adapter = devp; 13418c2ecf20Sopenharmony_ci unsigned long flags; 13428c2ecf20Sopenharmony_ci u8 status; 13438c2ecf20Sopenharmony_ci u32 dword = 0; 13448c2ecf20Sopenharmony_ci u8 nstatus; 13458c2ecf20Sopenharmony_ci u8 completed[MAX_FIRMWARE_STATUS]; 13468c2ecf20Sopenharmony_ci int handled = 0; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* 13508c2ecf20Sopenharmony_ci * loop till F/W has more commands for us to complete. 13518c2ecf20Sopenharmony_ci */ 13528c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci do { 13558c2ecf20Sopenharmony_ci /* Check if a valid interrupt is pending */ 13568c2ecf20Sopenharmony_ci dword = RDOUTDOOR(adapter); 13578c2ecf20Sopenharmony_ci if(dword != 0x10001234) { 13588c2ecf20Sopenharmony_ci /* 13598c2ecf20Sopenharmony_ci * No more pending commands 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_ci goto out_unlock; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci WROUTDOOR(adapter, 0x10001234); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) 13668c2ecf20Sopenharmony_ci == 0xFF) { 13678c2ecf20Sopenharmony_ci cpu_relax(); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci adapter->mbox->m_in.numstatus = 0xFF; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci status = adapter->mbox->m_in.status; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* 13748c2ecf20Sopenharmony_ci * decrement the pending queue counter 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_ci atomic_sub(nstatus, &adapter->pend_cmds); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci memcpy(completed, (void *)adapter->mbox->m_in.completed, 13798c2ecf20Sopenharmony_ci nstatus); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci /* Acknowledge interrupt */ 13828c2ecf20Sopenharmony_ci WRINDOOR(adapter, 0x2); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci handled = 1; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci while( RDINDOOR(adapter) & 0x02 ) 13878c2ecf20Sopenharmony_ci cpu_relax(); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci mega_cmd_done(adapter, completed, nstatus, status); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci mega_rundoneq(adapter); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci /* Loop through any pending requests */ 13948c2ecf20Sopenharmony_ci if(atomic_read(&adapter->quiescent) == 0) { 13958c2ecf20Sopenharmony_ci mega_runpendq(adapter); 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci } while(1); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci out_unlock: 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci/** 14078c2ecf20Sopenharmony_ci * mega_cmd_done() 14088c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 14098c2ecf20Sopenharmony_ci * @completed: array of ids of completed commands 14108c2ecf20Sopenharmony_ci * @nstatus: number of completed commands 14118c2ecf20Sopenharmony_ci * @status: status of the last command completed 14128c2ecf20Sopenharmony_ci * 14138c2ecf20Sopenharmony_ci * Complete the commands and call the scsi mid-layer callback hooks. 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_cistatic void 14168c2ecf20Sopenharmony_cimega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci mega_ext_passthru *epthru = NULL; 14198c2ecf20Sopenharmony_ci struct scatterlist *sgl; 14208c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = NULL; 14218c2ecf20Sopenharmony_ci mega_passthru *pthru = NULL; 14228c2ecf20Sopenharmony_ci mbox_t *mbox = NULL; 14238c2ecf20Sopenharmony_ci u8 c; 14248c2ecf20Sopenharmony_ci scb_t *scb; 14258c2ecf20Sopenharmony_ci int islogical; 14268c2ecf20Sopenharmony_ci int cmdid; 14278c2ecf20Sopenharmony_ci int i; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* 14308c2ecf20Sopenharmony_ci * for all the commands completed, call the mid-layer callback routine 14318c2ecf20Sopenharmony_ci * and free the scb. 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci for( i = 0; i < nstatus; i++ ) { 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci cmdid = completed[i]; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci /* 14388c2ecf20Sopenharmony_ci * Only free SCBs for the commands coming down from the 14398c2ecf20Sopenharmony_ci * mid-layer, not for which were issued internally 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * For internal command, restore the status returned by the 14428c2ecf20Sopenharmony_ci * firmware so that user can interpret it. 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci if (cmdid == CMDID_INT_CMDS) { 14458c2ecf20Sopenharmony_ci scb = &adapter->int_scb; 14468c2ecf20Sopenharmony_ci cmd = scb->cmd; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci list_del_init(&scb->list); 14498c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci adapter->int_status = status; 14528c2ecf20Sopenharmony_ci complete(&adapter->int_waitq); 14538c2ecf20Sopenharmony_ci } else { 14548c2ecf20Sopenharmony_ci scb = &adapter->scb_list[cmdid]; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* 14578c2ecf20Sopenharmony_ci * Make sure f/w has completed a valid command 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) { 14608c2ecf20Sopenharmony_ci dev_crit(&adapter->dev->dev, "invalid command " 14618c2ecf20Sopenharmony_ci "Id %d, scb->state:%x, scsi cmd:%p\n", 14628c2ecf20Sopenharmony_ci cmdid, scb->state, scb->cmd); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci continue; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci /* 14688c2ecf20Sopenharmony_ci * Was a abort issued for this command 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci if( scb->state & SCB_ABORT ) { 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 14738c2ecf20Sopenharmony_ci "aborted cmd [%x] complete\n", 14748c2ecf20Sopenharmony_ci scb->idx); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci scb->cmd->result = (DID_ABORT << 16); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci list_add_tail(SCSI_LIST(scb->cmd), 14798c2ecf20Sopenharmony_ci &adapter->completed_list); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci mega_free_scb(adapter, scb); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci continue; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* 14878c2ecf20Sopenharmony_ci * Was a reset issued for this command 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ci if( scb->state & SCB_RESET ) { 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 14928c2ecf20Sopenharmony_ci "reset cmd [%x] complete\n", 14938c2ecf20Sopenharmony_ci scb->idx); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci scb->cmd->result = (DID_RESET << 16); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci list_add_tail(SCSI_LIST(scb->cmd), 14988c2ecf20Sopenharmony_ci &adapter->completed_list); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci mega_free_scb (adapter, scb); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci continue; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci cmd = scb->cmd; 15068c2ecf20Sopenharmony_ci pthru = scb->pthru; 15078c2ecf20Sopenharmony_ci epthru = scb->epthru; 15088c2ecf20Sopenharmony_ci mbox = (mbox_t *)scb->raw_mbox; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 15118c2ecf20Sopenharmony_ci { 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci int logdrv = mbox->m_out.logdrv; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci islogical = adapter->logdrv_chan[cmd->channel]; 15168c2ecf20Sopenharmony_ci /* 15178c2ecf20Sopenharmony_ci * Maintain an error counter for the logical drive. 15188c2ecf20Sopenharmony_ci * Some application like SNMP agent need such 15198c2ecf20Sopenharmony_ci * statistics 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_ci if( status && islogical && (cmd->cmnd[0] == READ_6 || 15228c2ecf20Sopenharmony_ci cmd->cmnd[0] == READ_10 || 15238c2ecf20Sopenharmony_ci cmd->cmnd[0] == READ_12)) { 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * Logical drive number increases by 0x80 when 15268c2ecf20Sopenharmony_ci * a logical drive is deleted 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci adapter->rd_errors[logdrv%0x80]++; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if( status && islogical && (cmd->cmnd[0] == WRITE_6 || 15328c2ecf20Sopenharmony_ci cmd->cmnd[0] == WRITE_10 || 15338c2ecf20Sopenharmony_ci cmd->cmnd[0] == WRITE_12)) { 15348c2ecf20Sopenharmony_ci /* 15358c2ecf20Sopenharmony_ci * Logical drive number increases by 0x80 when 15368c2ecf20Sopenharmony_ci * a logical drive is deleted 15378c2ecf20Sopenharmony_ci */ 15388c2ecf20Sopenharmony_ci adapter->wr_errors[logdrv%0x80]++; 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci#endif 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* 15468c2ecf20Sopenharmony_ci * Do not return the presence of hard disk on the channel so, 15478c2ecf20Sopenharmony_ci * inquiry sent, and returned data==hard disk or removable 15488c2ecf20Sopenharmony_ci * hard disk and not logical, request should return failure! - 15498c2ecf20Sopenharmony_ci * PJ 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_ci islogical = adapter->logdrv_chan[cmd->device->channel]; 15528c2ecf20Sopenharmony_ci if( cmd->cmnd[0] == INQUIRY && !islogical ) { 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci sgl = scsi_sglist(cmd); 15558c2ecf20Sopenharmony_ci if( sg_page(sgl) ) { 15568c2ecf20Sopenharmony_ci c = *(unsigned char *) sg_virt(&sgl[0]); 15578c2ecf20Sopenharmony_ci } else { 15588c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "invalid sg\n"); 15598c2ecf20Sopenharmony_ci c = 0; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if(IS_RAID_CH(adapter, cmd->device->channel) && 15638c2ecf20Sopenharmony_ci ((c & 0x1F ) == TYPE_DISK)) { 15648c2ecf20Sopenharmony_ci status = 0xF0; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* clear result; otherwise, success returns corrupt value */ 15698c2ecf20Sopenharmony_ci cmd->result = 0; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci /* Convert MegaRAID status to Linux error code */ 15728c2ecf20Sopenharmony_ci switch (status) { 15738c2ecf20Sopenharmony_ci case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD */ 15748c2ecf20Sopenharmony_ci cmd->result |= (DID_OK << 16); 15758c2ecf20Sopenharmony_ci break; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci case 0x02: /* ERROR_ABORTED, i.e. 15788c2ecf20Sopenharmony_ci SCSI_STATUS_CHECK_CONDITION */ 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* set sense_buffer and result fields */ 15818c2ecf20Sopenharmony_ci if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU || 15828c2ecf20Sopenharmony_ci mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) { 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci memcpy(cmd->sense_buffer, pthru->reqsensearea, 15858c2ecf20Sopenharmony_ci 14); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci cmd->result = (DRIVER_SENSE << 24) | 15888c2ecf20Sopenharmony_ci (DID_OK << 16) | 15898c2ecf20Sopenharmony_ci (CHECK_CONDITION << 1); 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci else { 15928c2ecf20Sopenharmony_ci if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) { 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci memcpy(cmd->sense_buffer, 15958c2ecf20Sopenharmony_ci epthru->reqsensearea, 14); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci cmd->result = (DRIVER_SENSE << 24) | 15988c2ecf20Sopenharmony_ci (DID_OK << 16) | 15998c2ecf20Sopenharmony_ci (CHECK_CONDITION << 1); 16008c2ecf20Sopenharmony_ci } else { 16018c2ecf20Sopenharmony_ci cmd->sense_buffer[0] = 0x70; 16028c2ecf20Sopenharmony_ci cmd->sense_buffer[2] = ABORTED_COMMAND; 16038c2ecf20Sopenharmony_ci cmd->result |= (CHECK_CONDITION << 1); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. 16098c2ecf20Sopenharmony_ci SCSI_STATUS_BUSY */ 16108c2ecf20Sopenharmony_ci cmd->result |= (DID_BUS_BUSY << 16) | status; 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci default: 16148c2ecf20Sopenharmony_ci#if MEGA_HAVE_CLUSTERING 16158c2ecf20Sopenharmony_ci /* 16168c2ecf20Sopenharmony_ci * If TEST_UNIT_READY fails, we know 16178c2ecf20Sopenharmony_ci * MEGA_RESERVATION_STATUS failed 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci if( cmd->cmnd[0] == TEST_UNIT_READY ) { 16208c2ecf20Sopenharmony_ci cmd->result |= (DID_ERROR << 16) | 16218c2ecf20Sopenharmony_ci (RESERVATION_CONFLICT << 1); 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci else 16248c2ecf20Sopenharmony_ci /* 16258c2ecf20Sopenharmony_ci * Error code returned is 1 if Reserve or Release 16268c2ecf20Sopenharmony_ci * failed or the input parameter is invalid 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_ci if( status == 1 && 16298c2ecf20Sopenharmony_ci (cmd->cmnd[0] == RESERVE || 16308c2ecf20Sopenharmony_ci cmd->cmnd[0] == RELEASE) ) { 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci cmd->result |= (DID_ERROR << 16) | 16338c2ecf20Sopenharmony_ci (RESERVATION_CONFLICT << 1); 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci else 16368c2ecf20Sopenharmony_ci#endif 16378c2ecf20Sopenharmony_ci cmd->result |= (DID_BAD_TARGET << 16)|status; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci mega_free_scb(adapter, scb); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* Add Scsi_Command to end of completed queue */ 16438c2ecf20Sopenharmony_ci list_add_tail(SCSI_LIST(cmd), &adapter->completed_list); 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci/* 16498c2ecf20Sopenharmony_ci * mega_runpendq() 16508c2ecf20Sopenharmony_ci * 16518c2ecf20Sopenharmony_ci * Run through the list of completed requests and finish it 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_cistatic void 16548c2ecf20Sopenharmony_cimega_rundoneq (adapter_t *adapter) 16558c2ecf20Sopenharmony_ci{ 16568c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 16578c2ecf20Sopenharmony_ci struct list_head *pos; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci list_for_each(pos, &adapter->completed_list) { 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci struct scsi_pointer* spos = (struct scsi_pointer *)pos; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci cmd = list_entry(spos, struct scsi_cmnd, SCp); 16648c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->completed_list); 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/* 16728c2ecf20Sopenharmony_ci * Free a SCB structure 16738c2ecf20Sopenharmony_ci * Note: We assume the scsi commands associated with this scb is not free yet. 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_cistatic void 16768c2ecf20Sopenharmony_cimega_free_scb(adapter_t *adapter, scb_t *scb) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci switch( scb->dma_type ) { 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci case MEGA_DMA_TYPE_NONE: 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci case MEGA_SGLIST: 16848c2ecf20Sopenharmony_ci scsi_dma_unmap(scb->cmd); 16858c2ecf20Sopenharmony_ci break; 16868c2ecf20Sopenharmony_ci default: 16878c2ecf20Sopenharmony_ci break; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci /* 16918c2ecf20Sopenharmony_ci * Remove from the pending list 16928c2ecf20Sopenharmony_ci */ 16938c2ecf20Sopenharmony_ci list_del_init(&scb->list); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* Link the scb back into free list */ 16968c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 16978c2ecf20Sopenharmony_ci scb->cmd = NULL; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci list_add(&scb->list, &adapter->free_list); 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic int 17048c2ecf20Sopenharmony_ci__mega_busywait_mbox (adapter_t *adapter) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci volatile mbox_t *mbox = adapter->mbox; 17078c2ecf20Sopenharmony_ci long counter; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci for (counter = 0; counter < 10000; counter++) { 17108c2ecf20Sopenharmony_ci if (!mbox->m_in.busy) 17118c2ecf20Sopenharmony_ci return 0; 17128c2ecf20Sopenharmony_ci udelay(100); 17138c2ecf20Sopenharmony_ci cond_resched(); 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci return -1; /* give up after 1 second */ 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci/* 17198c2ecf20Sopenharmony_ci * Copies data to SGLIST 17208c2ecf20Sopenharmony_ci * Note: For 64 bit cards, we need a minimum of one SG element for read/write 17218c2ecf20Sopenharmony_ci */ 17228c2ecf20Sopenharmony_cistatic int 17238c2ecf20Sopenharmony_cimega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci struct scatterlist *sg; 17268c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 17278c2ecf20Sopenharmony_ci int sgcnt; 17288c2ecf20Sopenharmony_ci int idx; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci cmd = scb->cmd; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* 17338c2ecf20Sopenharmony_ci * Copy Scatter-Gather list info into controller structure. 17348c2ecf20Sopenharmony_ci * 17358c2ecf20Sopenharmony_ci * The number of sg elements returned must not exceed our limit 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_ci sgcnt = scsi_dma_map(cmd); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci scb->dma_type = MEGA_SGLIST; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci BUG_ON(sgcnt > adapter->sglen || sgcnt < 0); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci *len = 0; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) { 17468c2ecf20Sopenharmony_ci sg = scsi_sglist(cmd); 17478c2ecf20Sopenharmony_ci scb->dma_h_bulkdata = sg_dma_address(sg); 17488c2ecf20Sopenharmony_ci *buf = (u32)scb->dma_h_bulkdata; 17498c2ecf20Sopenharmony_ci *len = sg_dma_len(sg); 17508c2ecf20Sopenharmony_ci return 0; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, sgcnt, idx) { 17548c2ecf20Sopenharmony_ci if (adapter->has_64bit_addr) { 17558c2ecf20Sopenharmony_ci scb->sgl64[idx].address = sg_dma_address(sg); 17568c2ecf20Sopenharmony_ci *len += scb->sgl64[idx].length = sg_dma_len(sg); 17578c2ecf20Sopenharmony_ci } else { 17588c2ecf20Sopenharmony_ci scb->sgl[idx].address = sg_dma_address(sg); 17598c2ecf20Sopenharmony_ci *len += scb->sgl[idx].length = sg_dma_len(sg); 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* Reset pointer and length fields */ 17648c2ecf20Sopenharmony_ci *buf = scb->sgl_dma_addr; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* Return count of SG requests */ 17678c2ecf20Sopenharmony_ci return sgcnt; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci/* 17728c2ecf20Sopenharmony_ci * mega_8_to_40ld() 17738c2ecf20Sopenharmony_ci * 17748c2ecf20Sopenharmony_ci * takes all info in AdapterInquiry structure and puts it into ProductInfo and 17758c2ecf20Sopenharmony_ci * Enquiry3 structures for later use 17768c2ecf20Sopenharmony_ci */ 17778c2ecf20Sopenharmony_cistatic void 17788c2ecf20Sopenharmony_cimega_8_to_40ld(mraid_inquiry *inquiry, mega_inquiry3 *enquiry3, 17798c2ecf20Sopenharmony_ci mega_product_info *product_info) 17808c2ecf20Sopenharmony_ci{ 17818c2ecf20Sopenharmony_ci int i; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci product_info->max_commands = inquiry->adapter_info.max_commands; 17848c2ecf20Sopenharmony_ci enquiry3->rebuild_rate = inquiry->adapter_info.rebuild_rate; 17858c2ecf20Sopenharmony_ci product_info->nchannels = inquiry->adapter_info.nchannels; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 17888c2ecf20Sopenharmony_ci product_info->fw_version[i] = 17898c2ecf20Sopenharmony_ci inquiry->adapter_info.fw_version[i]; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci product_info->bios_version[i] = 17928c2ecf20Sopenharmony_ci inquiry->adapter_info.bios_version[i]; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci enquiry3->cache_flush_interval = 17958c2ecf20Sopenharmony_ci inquiry->adapter_info.cache_flush_interval; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci product_info->dram_size = inquiry->adapter_info.dram_size; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci enquiry3->num_ldrv = inquiry->logdrv_info.num_ldrv; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LOGICAL_DRIVES_8LD; i++) { 18028c2ecf20Sopenharmony_ci enquiry3->ldrv_size[i] = inquiry->logdrv_info.ldrv_size[i]; 18038c2ecf20Sopenharmony_ci enquiry3->ldrv_prop[i] = inquiry->logdrv_info.ldrv_prop[i]; 18048c2ecf20Sopenharmony_ci enquiry3->ldrv_state[i] = inquiry->logdrv_info.ldrv_state[i]; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) 18088c2ecf20Sopenharmony_ci enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i]; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic inline void 18128c2ecf20Sopenharmony_cimega_free_sgl(adapter_t *adapter) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci scb_t *scb; 18158c2ecf20Sopenharmony_ci int i; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci for(i = 0; i < adapter->max_cmds; i++) { 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci scb = &adapter->scb_list[i]; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if( scb->sgl64 ) { 18228c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 18238c2ecf20Sopenharmony_ci sizeof(mega_sgl64) * adapter->sglen, 18248c2ecf20Sopenharmony_ci scb->sgl64, scb->sgl_dma_addr); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci scb->sgl64 = NULL; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if( scb->pthru ) { 18308c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 18318c2ecf20Sopenharmony_ci sizeof(mega_passthru), scb->pthru, 18328c2ecf20Sopenharmony_ci scb->pthru_dma_addr); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci scb->pthru = NULL; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if( scb->epthru ) { 18388c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 18398c2ecf20Sopenharmony_ci sizeof(mega_ext_passthru), 18408c2ecf20Sopenharmony_ci scb->epthru, scb->epthru_dma_addr); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci scb->epthru = NULL; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci/* 18508c2ecf20Sopenharmony_ci * Get information about the card/driver 18518c2ecf20Sopenharmony_ci */ 18528c2ecf20Sopenharmony_ciconst char * 18538c2ecf20Sopenharmony_cimegaraid_info(struct Scsi_Host *host) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci static char buffer[512]; 18568c2ecf20Sopenharmony_ci adapter_t *adapter; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci adapter = (adapter_t *)host->hostdata; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci sprintf (buffer, 18618c2ecf20Sopenharmony_ci "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns", 18628c2ecf20Sopenharmony_ci adapter->fw_version, adapter->product_info.max_commands, 18638c2ecf20Sopenharmony_ci adapter->host->max_id, adapter->host->max_channel, 18648c2ecf20Sopenharmony_ci (u32)adapter->host->max_lun); 18658c2ecf20Sopenharmony_ci return buffer; 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci/* 18698c2ecf20Sopenharmony_ci * Abort a previous SCSI request. Only commands on the pending list can be 18708c2ecf20Sopenharmony_ci * aborted. All the commands issued to the F/W must complete. 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_cistatic int 18738c2ecf20Sopenharmony_cimegaraid_abort(struct scsi_cmnd *cmd) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci adapter_t *adapter; 18768c2ecf20Sopenharmony_ci int rval; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci adapter = (adapter_t *)cmd->device->host->hostdata; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci rval = megaraid_abort_and_reset(adapter, cmd, SCB_ABORT); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* 18838c2ecf20Sopenharmony_ci * This is required here to complete any completed requests 18848c2ecf20Sopenharmony_ci * to be communicated over to the mid layer. 18858c2ecf20Sopenharmony_ci */ 18868c2ecf20Sopenharmony_ci mega_rundoneq(adapter); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci return rval; 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic int 18938c2ecf20Sopenharmony_cimegaraid_reset(struct scsi_cmnd *cmd) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci adapter_t *adapter; 18968c2ecf20Sopenharmony_ci megacmd_t mc; 18978c2ecf20Sopenharmony_ci int rval; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci adapter = (adapter_t *)cmd->device->host->hostdata; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci#if MEGA_HAVE_CLUSTERING 19028c2ecf20Sopenharmony_ci mc.cmd = MEGA_CLUSTER_CMD; 19038c2ecf20Sopenharmony_ci mc.opcode = MEGA_RESET_RESERVATIONS; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if( mega_internal_command(adapter, &mc, NULL) != 0 ) { 19068c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "reservation reset failed\n"); 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci else { 19098c2ecf20Sopenharmony_ci dev_info(&adapter->dev->dev, "reservation reset\n"); 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci#endif 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->lock); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci rval = megaraid_abort_and_reset(adapter, cmd, SCB_RESET); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* 19188c2ecf20Sopenharmony_ci * This is required here to complete any completed requests 19198c2ecf20Sopenharmony_ci * to be communicated over to the mid layer. 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_ci mega_rundoneq(adapter); 19228c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->lock); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci return rval; 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci/** 19288c2ecf20Sopenharmony_ci * megaraid_abort_and_reset() 19298c2ecf20Sopenharmony_ci * @adapter: megaraid soft state 19308c2ecf20Sopenharmony_ci * @cmd: scsi command to be aborted or reset 19318c2ecf20Sopenharmony_ci * @aor: abort or reset flag 19328c2ecf20Sopenharmony_ci * 19338c2ecf20Sopenharmony_ci * Try to locate the scsi command in the pending queue. If found and is not 19348c2ecf20Sopenharmony_ci * issued to the controller, abort/reset it. Otherwise return failure 19358c2ecf20Sopenharmony_ci */ 19368c2ecf20Sopenharmony_cistatic int 19378c2ecf20Sopenharmony_cimegaraid_abort_and_reset(adapter_t *adapter, struct scsi_cmnd *cmd, int aor) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci struct list_head *pos, *next; 19408c2ecf20Sopenharmony_ci scb_t *scb; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "%s cmd=%x <c=%d t=%d l=%d>\n", 19438c2ecf20Sopenharmony_ci (aor == SCB_ABORT)? "ABORTING":"RESET", 19448c2ecf20Sopenharmony_ci cmd->cmnd[0], cmd->device->channel, 19458c2ecf20Sopenharmony_ci cmd->device->id, (u32)cmd->device->lun); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if(list_empty(&adapter->pending_list)) 19488c2ecf20Sopenharmony_ci return FAILED; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci list_for_each_safe(pos, next, &adapter->pending_list) { 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci scb = list_entry(pos, scb_t, list); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (scb->cmd == cmd) { /* Found command */ 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci scb->state |= aor; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* 19598c2ecf20Sopenharmony_ci * Check if this command has firmware ownership. If 19608c2ecf20Sopenharmony_ci * yes, we cannot reset this command. Whenever f/w 19618c2ecf20Sopenharmony_ci * completes this command, we will return appropriate 19628c2ecf20Sopenharmony_ci * status from ISR. 19638c2ecf20Sopenharmony_ci */ 19648c2ecf20Sopenharmony_ci if( scb->state & SCB_ISSUED ) { 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 19678c2ecf20Sopenharmony_ci "%s[%x], fw owner\n", 19688c2ecf20Sopenharmony_ci (aor==SCB_ABORT) ? "ABORTING":"RESET", 19698c2ecf20Sopenharmony_ci scb->idx); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci return FAILED; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci else { 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci /* 19768c2ecf20Sopenharmony_ci * Not yet issued! Remove from the pending 19778c2ecf20Sopenharmony_ci * list 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 19808c2ecf20Sopenharmony_ci "%s-[%x], driver owner\n", 19818c2ecf20Sopenharmony_ci (aor==SCB_ABORT) ? "ABORTING":"RESET", 19828c2ecf20Sopenharmony_ci scb->idx); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci mega_free_scb(adapter, scb); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if( aor == SCB_ABORT ) { 19878c2ecf20Sopenharmony_ci cmd->result = (DID_ABORT << 16); 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci else { 19908c2ecf20Sopenharmony_ci cmd->result = (DID_RESET << 16); 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci list_add_tail(SCSI_LIST(cmd), 19948c2ecf20Sopenharmony_ci &adapter->completed_list); 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci return SUCCESS; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci return FAILED; 20028c2ecf20Sopenharmony_ci} 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_cistatic inline int 20058c2ecf20Sopenharmony_cimake_local_pdev(adapter_t *adapter, struct pci_dev **pdev) 20068c2ecf20Sopenharmony_ci{ 20078c2ecf20Sopenharmony_ci *pdev = pci_alloc_dev(NULL); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if( *pdev == NULL ) return -1; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci memcpy(*pdev, adapter->dev, sizeof(struct pci_dev)); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci if (dma_set_mask(&(*pdev)->dev, DMA_BIT_MASK(32)) != 0) { 20148c2ecf20Sopenharmony_ci kfree(*pdev); 20158c2ecf20Sopenharmony_ci return -1; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci return 0; 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic inline void 20228c2ecf20Sopenharmony_cifree_local_pdev(struct pci_dev *pdev) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci kfree(pdev); 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci/** 20288c2ecf20Sopenharmony_ci * mega_allocate_inquiry() 20298c2ecf20Sopenharmony_ci * @dma_handle: handle returned for dma address 20308c2ecf20Sopenharmony_ci * @pdev: handle to pci device 20318c2ecf20Sopenharmony_ci * 20328c2ecf20Sopenharmony_ci * allocates memory for inquiry structure 20338c2ecf20Sopenharmony_ci */ 20348c2ecf20Sopenharmony_cistatic inline void * 20358c2ecf20Sopenharmony_cimega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) 20368c2ecf20Sopenharmony_ci{ 20378c2ecf20Sopenharmony_ci return dma_alloc_coherent(&pdev->dev, sizeof(mega_inquiry3), 20388c2ecf20Sopenharmony_ci dma_handle, GFP_KERNEL); 20398c2ecf20Sopenharmony_ci} 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic inline void 20438c2ecf20Sopenharmony_cimega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) 20448c2ecf20Sopenharmony_ci{ 20458c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(mega_inquiry3), inquiry, 20468c2ecf20Sopenharmony_ci dma_handle); 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 20518c2ecf20Sopenharmony_ci/* Following code handles /proc fs */ 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci/** 20548c2ecf20Sopenharmony_ci * proc_show_config() 20558c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 20568c2ecf20Sopenharmony_ci * @v: File iterator 20578c2ecf20Sopenharmony_ci * 20588c2ecf20Sopenharmony_ci * Display configuration information about the controller. 20598c2ecf20Sopenharmony_ci */ 20608c2ecf20Sopenharmony_cistatic int 20618c2ecf20Sopenharmony_ciproc_show_config(struct seq_file *m, void *v) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci adapter_t *adapter = m->private; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci seq_puts(m, MEGARAID_VERSION); 20678c2ecf20Sopenharmony_ci if(adapter->product_info.product_name[0]) 20688c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", adapter->product_info.product_name); 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci seq_puts(m, "Controller Type: "); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_MEMMAP ) 20738c2ecf20Sopenharmony_ci seq_puts(m, "438/466/467/471/493/518/520/531/532\n"); 20748c2ecf20Sopenharmony_ci else 20758c2ecf20Sopenharmony_ci seq_puts(m, "418/428/434\n"); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci if(adapter->flag & BOARD_40LD) 20788c2ecf20Sopenharmony_ci seq_puts(m, "Controller Supports 40 Logical Drives\n"); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if(adapter->flag & BOARD_64BIT) 20818c2ecf20Sopenharmony_ci seq_puts(m, "Controller capable of 64-bit memory addressing\n"); 20828c2ecf20Sopenharmony_ci if( adapter->has_64bit_addr ) 20838c2ecf20Sopenharmony_ci seq_puts(m, "Controller using 64-bit memory addressing\n"); 20848c2ecf20Sopenharmony_ci else 20858c2ecf20Sopenharmony_ci seq_puts(m, "Controller is not using 64-bit memory addressing\n"); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci seq_printf(m, "Base = %08lx, Irq = %d, ", 20888c2ecf20Sopenharmony_ci adapter->base, adapter->host->irq); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci seq_printf(m, "Logical Drives = %d, Channels = %d\n", 20918c2ecf20Sopenharmony_ci adapter->numldrv, adapter->product_info.nchannels); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci seq_printf(m, "Version =%s:%s, DRAM = %dMb\n", 20948c2ecf20Sopenharmony_ci adapter->fw_version, adapter->bios_version, 20958c2ecf20Sopenharmony_ci adapter->product_info.dram_size); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci seq_printf(m, "Controller Queue Depth = %d, Driver Queue Depth = %d\n", 20988c2ecf20Sopenharmony_ci adapter->product_info.max_commands, adapter->max_cmds); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci seq_printf(m, "support_ext_cdb = %d\n", adapter->support_ext_cdb); 21018c2ecf20Sopenharmony_ci seq_printf(m, "support_random_del = %d\n", adapter->support_random_del); 21028c2ecf20Sopenharmony_ci seq_printf(m, "boot_ldrv_enabled = %d\n", adapter->boot_ldrv_enabled); 21038c2ecf20Sopenharmony_ci seq_printf(m, "boot_ldrv = %d\n", adapter->boot_ldrv); 21048c2ecf20Sopenharmony_ci seq_printf(m, "boot_pdrv_enabled = %d\n", adapter->boot_pdrv_enabled); 21058c2ecf20Sopenharmony_ci seq_printf(m, "boot_pdrv_ch = %d\n", adapter->boot_pdrv_ch); 21068c2ecf20Sopenharmony_ci seq_printf(m, "boot_pdrv_tgt = %d\n", adapter->boot_pdrv_tgt); 21078c2ecf20Sopenharmony_ci seq_printf(m, "quiescent = %d\n", 21088c2ecf20Sopenharmony_ci atomic_read(&adapter->quiescent)); 21098c2ecf20Sopenharmony_ci seq_printf(m, "has_cluster = %d\n", adapter->has_cluster); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci seq_puts(m, "\nModule Parameters:\n"); 21128c2ecf20Sopenharmony_ci seq_printf(m, "max_cmd_per_lun = %d\n", max_cmd_per_lun); 21138c2ecf20Sopenharmony_ci seq_printf(m, "max_sectors_per_io = %d\n", max_sectors_per_io); 21148c2ecf20Sopenharmony_ci return 0; 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci/** 21188c2ecf20Sopenharmony_ci * proc_show_stat() 21198c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 21208c2ecf20Sopenharmony_ci * @v: File iterator 21218c2ecf20Sopenharmony_ci * 21228c2ecf20Sopenharmony_ci * Display statistical information about the I/O activity. 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_cistatic int 21258c2ecf20Sopenharmony_ciproc_show_stat(struct seq_file *m, void *v) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci adapter_t *adapter = m->private; 21288c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 21298c2ecf20Sopenharmony_ci int i; 21308c2ecf20Sopenharmony_ci#endif 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci seq_puts(m, "Statistical Information for this controller\n"); 21338c2ecf20Sopenharmony_ci seq_printf(m, "pend_cmds = %d\n", atomic_read(&adapter->pend_cmds)); 21348c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 21358c2ecf20Sopenharmony_ci for(i = 0; i < adapter->numldrv; i++) { 21368c2ecf20Sopenharmony_ci seq_printf(m, "Logical Drive %d:\n", i); 21378c2ecf20Sopenharmony_ci seq_printf(m, "\tReads Issued = %lu, Writes Issued = %lu\n", 21388c2ecf20Sopenharmony_ci adapter->nreads[i], adapter->nwrites[i]); 21398c2ecf20Sopenharmony_ci seq_printf(m, "\tSectors Read = %lu, Sectors Written = %lu\n", 21408c2ecf20Sopenharmony_ci adapter->nreadblocks[i], adapter->nwriteblocks[i]); 21418c2ecf20Sopenharmony_ci seq_printf(m, "\tRead errors = %lu, Write errors = %lu\n\n", 21428c2ecf20Sopenharmony_ci adapter->rd_errors[i], adapter->wr_errors[i]); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci#else 21458c2ecf20Sopenharmony_ci seq_puts(m, "IO and error counters not compiled in driver.\n"); 21468c2ecf20Sopenharmony_ci#endif 21478c2ecf20Sopenharmony_ci return 0; 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci/** 21528c2ecf20Sopenharmony_ci * proc_show_mbox() 21538c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 21548c2ecf20Sopenharmony_ci * @v: File iterator 21558c2ecf20Sopenharmony_ci * 21568c2ecf20Sopenharmony_ci * Display mailbox information for the last command issued. This information 21578c2ecf20Sopenharmony_ci * is good for debugging. 21588c2ecf20Sopenharmony_ci */ 21598c2ecf20Sopenharmony_cistatic int 21608c2ecf20Sopenharmony_ciproc_show_mbox(struct seq_file *m, void *v) 21618c2ecf20Sopenharmony_ci{ 21628c2ecf20Sopenharmony_ci adapter_t *adapter = m->private; 21638c2ecf20Sopenharmony_ci volatile mbox_t *mbox = adapter->mbox; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci seq_puts(m, "Contents of Mail Box Structure\n"); 21668c2ecf20Sopenharmony_ci seq_printf(m, " Fw Command = 0x%02x\n", mbox->m_out.cmd); 21678c2ecf20Sopenharmony_ci seq_printf(m, " Cmd Sequence = 0x%02x\n", mbox->m_out.cmdid); 21688c2ecf20Sopenharmony_ci seq_printf(m, " No of Sectors= %04d\n", mbox->m_out.numsectors); 21698c2ecf20Sopenharmony_ci seq_printf(m, " LBA = 0x%02x\n", mbox->m_out.lba); 21708c2ecf20Sopenharmony_ci seq_printf(m, " DTA = 0x%08x\n", mbox->m_out.xferaddr); 21718c2ecf20Sopenharmony_ci seq_printf(m, " Logical Drive= 0x%02x\n", mbox->m_out.logdrv); 21728c2ecf20Sopenharmony_ci seq_printf(m, " No of SG Elmt= 0x%02x\n", mbox->m_out.numsgelements); 21738c2ecf20Sopenharmony_ci seq_printf(m, " Busy = %01x\n", mbox->m_in.busy); 21748c2ecf20Sopenharmony_ci seq_printf(m, " Status = 0x%02x\n", mbox->m_in.status); 21758c2ecf20Sopenharmony_ci return 0; 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci/** 21808c2ecf20Sopenharmony_ci * proc_show_rebuild_rate() 21818c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 21828c2ecf20Sopenharmony_ci * @v: File iterator 21838c2ecf20Sopenharmony_ci * 21848c2ecf20Sopenharmony_ci * Display current rebuild rate 21858c2ecf20Sopenharmony_ci */ 21868c2ecf20Sopenharmony_cistatic int 21878c2ecf20Sopenharmony_ciproc_show_rebuild_rate(struct seq_file *m, void *v) 21888c2ecf20Sopenharmony_ci{ 21898c2ecf20Sopenharmony_ci adapter_t *adapter = m->private; 21908c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 21918c2ecf20Sopenharmony_ci caddr_t inquiry; 21928c2ecf20Sopenharmony_ci struct pci_dev *pdev; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) 21958c2ecf20Sopenharmony_ci return 0; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) 21988c2ecf20Sopenharmony_ci goto free_pdev; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if( mega_adapinq(adapter, dma_handle) != 0 ) { 22018c2ecf20Sopenharmony_ci seq_puts(m, "Adapter inquiry failed.\n"); 22028c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "inquiry failed\n"); 22038c2ecf20Sopenharmony_ci goto free_inquiry; 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) 22078c2ecf20Sopenharmony_ci seq_printf(m, "Rebuild Rate: [%d%%]\n", 22088c2ecf20Sopenharmony_ci ((mega_inquiry3 *)inquiry)->rebuild_rate); 22098c2ecf20Sopenharmony_ci else 22108c2ecf20Sopenharmony_ci seq_printf(m, "Rebuild Rate: [%d%%]\n", 22118c2ecf20Sopenharmony_ci ((mraid_ext_inquiry *) 22128c2ecf20Sopenharmony_ci inquiry)->raid_inq.adapter_info.rebuild_rate); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cifree_inquiry: 22158c2ecf20Sopenharmony_ci mega_free_inquiry(inquiry, dma_handle, pdev); 22168c2ecf20Sopenharmony_cifree_pdev: 22178c2ecf20Sopenharmony_ci free_local_pdev(pdev); 22188c2ecf20Sopenharmony_ci return 0; 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci/** 22238c2ecf20Sopenharmony_ci * proc_show_battery() 22248c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 22258c2ecf20Sopenharmony_ci * @v: File iterator 22268c2ecf20Sopenharmony_ci * 22278c2ecf20Sopenharmony_ci * Display information about the battery module on the controller. 22288c2ecf20Sopenharmony_ci */ 22298c2ecf20Sopenharmony_cistatic int 22308c2ecf20Sopenharmony_ciproc_show_battery(struct seq_file *m, void *v) 22318c2ecf20Sopenharmony_ci{ 22328c2ecf20Sopenharmony_ci adapter_t *adapter = m->private; 22338c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 22348c2ecf20Sopenharmony_ci caddr_t inquiry; 22358c2ecf20Sopenharmony_ci struct pci_dev *pdev; 22368c2ecf20Sopenharmony_ci u8 battery_status; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) 22398c2ecf20Sopenharmony_ci return 0; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) 22428c2ecf20Sopenharmony_ci goto free_pdev; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if( mega_adapinq(adapter, dma_handle) != 0 ) { 22458c2ecf20Sopenharmony_ci seq_puts(m, "Adapter inquiry failed.\n"); 22468c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "inquiry failed\n"); 22478c2ecf20Sopenharmony_ci goto free_inquiry; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 22518c2ecf20Sopenharmony_ci battery_status = ((mega_inquiry3 *)inquiry)->battery_status; 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci else { 22548c2ecf20Sopenharmony_ci battery_status = ((mraid_ext_inquiry *)inquiry)-> 22558c2ecf20Sopenharmony_ci raid_inq.adapter_info.battery_status; 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci /* 22598c2ecf20Sopenharmony_ci * Decode the battery status 22608c2ecf20Sopenharmony_ci */ 22618c2ecf20Sopenharmony_ci seq_printf(m, "Battery Status:[%d]", battery_status); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci if(battery_status == MEGA_BATT_CHARGE_DONE) 22648c2ecf20Sopenharmony_ci seq_puts(m, " Charge Done"); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_MODULE_MISSING) 22678c2ecf20Sopenharmony_ci seq_puts(m, " Module Missing"); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_LOW_VOLTAGE) 22708c2ecf20Sopenharmony_ci seq_puts(m, " Low Voltage"); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_TEMP_HIGH) 22738c2ecf20Sopenharmony_ci seq_puts(m, " Temperature High"); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_PACK_MISSING) 22768c2ecf20Sopenharmony_ci seq_puts(m, " Pack Missing"); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_CHARGE_INPROG) 22798c2ecf20Sopenharmony_ci seq_puts(m, " Charge In-progress"); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_CHARGE_FAIL) 22828c2ecf20Sopenharmony_ci seq_puts(m, " Charge Fail"); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if(battery_status & MEGA_BATT_CYCLES_EXCEEDED) 22858c2ecf20Sopenharmony_ci seq_puts(m, " Cycles Exceeded"); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_cifree_inquiry: 22908c2ecf20Sopenharmony_ci mega_free_inquiry(inquiry, dma_handle, pdev); 22918c2ecf20Sopenharmony_cifree_pdev: 22928c2ecf20Sopenharmony_ci free_local_pdev(pdev); 22938c2ecf20Sopenharmony_ci return 0; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci/* 22988c2ecf20Sopenharmony_ci * Display scsi inquiry 22998c2ecf20Sopenharmony_ci */ 23008c2ecf20Sopenharmony_cistatic void 23018c2ecf20Sopenharmony_cimega_print_inquiry(struct seq_file *m, char *scsi_inq) 23028c2ecf20Sopenharmony_ci{ 23038c2ecf20Sopenharmony_ci int i; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci seq_puts(m, " Vendor: "); 23068c2ecf20Sopenharmony_ci seq_write(m, scsi_inq + 8, 8); 23078c2ecf20Sopenharmony_ci seq_puts(m, " Model: "); 23088c2ecf20Sopenharmony_ci seq_write(m, scsi_inq + 16, 16); 23098c2ecf20Sopenharmony_ci seq_puts(m, " Rev: "); 23108c2ecf20Sopenharmony_ci seq_write(m, scsi_inq + 32, 4); 23118c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci i = scsi_inq[0] & 0x1f; 23148c2ecf20Sopenharmony_ci seq_printf(m, " Type: %s ", scsi_device_type(i)); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci seq_printf(m, " ANSI SCSI revision: %02x", 23178c2ecf20Sopenharmony_ci scsi_inq[2] & 0x07); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if( (scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1 ) 23208c2ecf20Sopenharmony_ci seq_puts(m, " CCS\n"); 23218c2ecf20Sopenharmony_ci else 23228c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci/** 23268c2ecf20Sopenharmony_ci * proc_show_pdrv() 23278c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 23288c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 23298c2ecf20Sopenharmony_ci * @channel: channel 23308c2ecf20Sopenharmony_ci * 23318c2ecf20Sopenharmony_ci * Display information about the physical drives. 23328c2ecf20Sopenharmony_ci */ 23338c2ecf20Sopenharmony_cistatic int 23348c2ecf20Sopenharmony_ciproc_show_pdrv(struct seq_file *m, adapter_t *adapter, int channel) 23358c2ecf20Sopenharmony_ci{ 23368c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 23378c2ecf20Sopenharmony_ci char *scsi_inq; 23388c2ecf20Sopenharmony_ci dma_addr_t scsi_inq_dma_handle; 23398c2ecf20Sopenharmony_ci caddr_t inquiry; 23408c2ecf20Sopenharmony_ci struct pci_dev *pdev; 23418c2ecf20Sopenharmony_ci u8 *pdrv_state; 23428c2ecf20Sopenharmony_ci u8 state; 23438c2ecf20Sopenharmony_ci int tgt; 23448c2ecf20Sopenharmony_ci int max_channels; 23458c2ecf20Sopenharmony_ci int i; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) 23488c2ecf20Sopenharmony_ci return 0; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) 23518c2ecf20Sopenharmony_ci goto free_pdev; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if( mega_adapinq(adapter, dma_handle) != 0 ) { 23548c2ecf20Sopenharmony_ci seq_puts(m, "Adapter inquiry failed.\n"); 23558c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "inquiry failed\n"); 23568c2ecf20Sopenharmony_ci goto free_inquiry; 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci scsi_inq = dma_alloc_coherent(&pdev->dev, 256, &scsi_inq_dma_handle, 23618c2ecf20Sopenharmony_ci GFP_KERNEL); 23628c2ecf20Sopenharmony_ci if( scsi_inq == NULL ) { 23638c2ecf20Sopenharmony_ci seq_puts(m, "memory not available for scsi inq.\n"); 23648c2ecf20Sopenharmony_ci goto free_inquiry; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 23688c2ecf20Sopenharmony_ci pdrv_state = ((mega_inquiry3 *)inquiry)->pdrv_state; 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci else { 23718c2ecf20Sopenharmony_ci pdrv_state = ((mraid_ext_inquiry *)inquiry)-> 23728c2ecf20Sopenharmony_ci raid_inq.pdrv_info.pdrv_state; 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci max_channels = adapter->product_info.nchannels; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci if( channel >= max_channels ) { 23788c2ecf20Sopenharmony_ci goto free_pci; 23798c2ecf20Sopenharmony_ci } 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci for( tgt = 0; tgt <= MAX_TARGET; tgt++ ) { 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci i = channel*16 + tgt; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci state = *(pdrv_state + i); 23868c2ecf20Sopenharmony_ci switch( state & 0x0F ) { 23878c2ecf20Sopenharmony_ci case PDRV_ONLINE: 23888c2ecf20Sopenharmony_ci seq_printf(m, "Channel:%2d Id:%2d State: Online", 23898c2ecf20Sopenharmony_ci channel, tgt); 23908c2ecf20Sopenharmony_ci break; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci case PDRV_FAILED: 23938c2ecf20Sopenharmony_ci seq_printf(m, "Channel:%2d Id:%2d State: Failed", 23948c2ecf20Sopenharmony_ci channel, tgt); 23958c2ecf20Sopenharmony_ci break; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci case PDRV_RBLD: 23988c2ecf20Sopenharmony_ci seq_printf(m, "Channel:%2d Id:%2d State: Rebuild", 23998c2ecf20Sopenharmony_ci channel, tgt); 24008c2ecf20Sopenharmony_ci break; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci case PDRV_HOTSPARE: 24038c2ecf20Sopenharmony_ci seq_printf(m, "Channel:%2d Id:%2d State: Hot spare", 24048c2ecf20Sopenharmony_ci channel, tgt); 24058c2ecf20Sopenharmony_ci break; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci default: 24088c2ecf20Sopenharmony_ci seq_printf(m, "Channel:%2d Id:%2d State: Un-configured", 24098c2ecf20Sopenharmony_ci channel, tgt); 24108c2ecf20Sopenharmony_ci break; 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci /* 24148c2ecf20Sopenharmony_ci * This interface displays inquiries for disk drives 24158c2ecf20Sopenharmony_ci * only. Inquries for logical drives and non-disk 24168c2ecf20Sopenharmony_ci * devices are available through /proc/scsi/scsi 24178c2ecf20Sopenharmony_ci */ 24188c2ecf20Sopenharmony_ci memset(scsi_inq, 0, 256); 24198c2ecf20Sopenharmony_ci if( mega_internal_dev_inquiry(adapter, channel, tgt, 24208c2ecf20Sopenharmony_ci scsi_inq_dma_handle) || 24218c2ecf20Sopenharmony_ci (scsi_inq[0] & 0x1F) != TYPE_DISK ) { 24228c2ecf20Sopenharmony_ci continue; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci /* 24268c2ecf20Sopenharmony_ci * Check for overflow. We print less than 240 24278c2ecf20Sopenharmony_ci * characters for inquiry 24288c2ecf20Sopenharmony_ci */ 24298c2ecf20Sopenharmony_ci seq_puts(m, ".\n"); 24308c2ecf20Sopenharmony_ci mega_print_inquiry(m, scsi_inq); 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_cifree_pci: 24348c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 256, scsi_inq, scsi_inq_dma_handle); 24358c2ecf20Sopenharmony_cifree_inquiry: 24368c2ecf20Sopenharmony_ci mega_free_inquiry(inquiry, dma_handle, pdev); 24378c2ecf20Sopenharmony_cifree_pdev: 24388c2ecf20Sopenharmony_ci free_local_pdev(pdev); 24398c2ecf20Sopenharmony_ci return 0; 24408c2ecf20Sopenharmony_ci} 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci/** 24438c2ecf20Sopenharmony_ci * proc_show_pdrv_ch0() 24448c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 24458c2ecf20Sopenharmony_ci * @v: File iterator 24468c2ecf20Sopenharmony_ci * 24478c2ecf20Sopenharmony_ci * Display information about the physical drives on physical channel 0. 24488c2ecf20Sopenharmony_ci */ 24498c2ecf20Sopenharmony_cistatic int 24508c2ecf20Sopenharmony_ciproc_show_pdrv_ch0(struct seq_file *m, void *v) 24518c2ecf20Sopenharmony_ci{ 24528c2ecf20Sopenharmony_ci return proc_show_pdrv(m, m->private, 0); 24538c2ecf20Sopenharmony_ci} 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci/** 24578c2ecf20Sopenharmony_ci * proc_show_pdrv_ch1() 24588c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 24598c2ecf20Sopenharmony_ci * @v: File iterator 24608c2ecf20Sopenharmony_ci * 24618c2ecf20Sopenharmony_ci * Display information about the physical drives on physical channel 1. 24628c2ecf20Sopenharmony_ci */ 24638c2ecf20Sopenharmony_cistatic int 24648c2ecf20Sopenharmony_ciproc_show_pdrv_ch1(struct seq_file *m, void *v) 24658c2ecf20Sopenharmony_ci{ 24668c2ecf20Sopenharmony_ci return proc_show_pdrv(m, m->private, 1); 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci/** 24718c2ecf20Sopenharmony_ci * proc_show_pdrv_ch2() 24728c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 24738c2ecf20Sopenharmony_ci * @v: File iterator 24748c2ecf20Sopenharmony_ci * 24758c2ecf20Sopenharmony_ci * Display information about the physical drives on physical channel 2. 24768c2ecf20Sopenharmony_ci */ 24778c2ecf20Sopenharmony_cistatic int 24788c2ecf20Sopenharmony_ciproc_show_pdrv_ch2(struct seq_file *m, void *v) 24798c2ecf20Sopenharmony_ci{ 24808c2ecf20Sopenharmony_ci return proc_show_pdrv(m, m->private, 2); 24818c2ecf20Sopenharmony_ci} 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci/** 24858c2ecf20Sopenharmony_ci * proc_show_pdrv_ch3() 24868c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 24878c2ecf20Sopenharmony_ci * @v: File iterator 24888c2ecf20Sopenharmony_ci * 24898c2ecf20Sopenharmony_ci * Display information about the physical drives on physical channel 3. 24908c2ecf20Sopenharmony_ci */ 24918c2ecf20Sopenharmony_cistatic int 24928c2ecf20Sopenharmony_ciproc_show_pdrv_ch3(struct seq_file *m, void *v) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci return proc_show_pdrv(m, m->private, 3); 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci/** 24998c2ecf20Sopenharmony_ci * proc_show_rdrv() 25008c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 25018c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 25028c2ecf20Sopenharmony_ci * @start: starting logical drive to display 25038c2ecf20Sopenharmony_ci * @end: ending logical drive to display 25048c2ecf20Sopenharmony_ci * 25058c2ecf20Sopenharmony_ci * We do not print the inquiry information since its already available through 25068c2ecf20Sopenharmony_ci * /proc/scsi/scsi interface 25078c2ecf20Sopenharmony_ci */ 25088c2ecf20Sopenharmony_cistatic int 25098c2ecf20Sopenharmony_ciproc_show_rdrv(struct seq_file *m, adapter_t *adapter, int start, int end ) 25108c2ecf20Sopenharmony_ci{ 25118c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 25128c2ecf20Sopenharmony_ci logdrv_param *lparam; 25138c2ecf20Sopenharmony_ci megacmd_t mc; 25148c2ecf20Sopenharmony_ci char *disk_array; 25158c2ecf20Sopenharmony_ci dma_addr_t disk_array_dma_handle; 25168c2ecf20Sopenharmony_ci caddr_t inquiry; 25178c2ecf20Sopenharmony_ci struct pci_dev *pdev; 25188c2ecf20Sopenharmony_ci u8 *rdrv_state; 25198c2ecf20Sopenharmony_ci int num_ldrv; 25208c2ecf20Sopenharmony_ci u32 array_sz; 25218c2ecf20Sopenharmony_ci int i; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) 25248c2ecf20Sopenharmony_ci return 0; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) 25278c2ecf20Sopenharmony_ci goto free_pdev; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if( mega_adapinq(adapter, dma_handle) != 0 ) { 25308c2ecf20Sopenharmony_ci seq_puts(m, "Adapter inquiry failed.\n"); 25318c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "inquiry failed\n"); 25328c2ecf20Sopenharmony_ci goto free_inquiry; 25338c2ecf20Sopenharmony_ci } 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci memset(&mc, 0, sizeof(megacmd_t)); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 25388c2ecf20Sopenharmony_ci array_sz = sizeof(disk_array_40ld); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci rdrv_state = ((mega_inquiry3 *)inquiry)->ldrv_state; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci num_ldrv = ((mega_inquiry3 *)inquiry)->num_ldrv; 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci else { 25458c2ecf20Sopenharmony_ci array_sz = sizeof(disk_array_8ld); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci rdrv_state = ((mraid_ext_inquiry *)inquiry)-> 25488c2ecf20Sopenharmony_ci raid_inq.logdrv_info.ldrv_state; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci num_ldrv = ((mraid_ext_inquiry *)inquiry)-> 25518c2ecf20Sopenharmony_ci raid_inq.logdrv_info.num_ldrv; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci disk_array = dma_alloc_coherent(&pdev->dev, array_sz, 25558c2ecf20Sopenharmony_ci &disk_array_dma_handle, GFP_KERNEL); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci if( disk_array == NULL ) { 25588c2ecf20Sopenharmony_ci seq_puts(m, "memory not available.\n"); 25598c2ecf20Sopenharmony_ci goto free_inquiry; 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci mc.xferaddr = (u32)disk_array_dma_handle; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 25658c2ecf20Sopenharmony_ci mc.cmd = FC_NEW_CONFIG; 25668c2ecf20Sopenharmony_ci mc.opcode = OP_DCMD_READ_CONFIG; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci if( mega_internal_command(adapter, &mc, NULL) ) { 25698c2ecf20Sopenharmony_ci seq_puts(m, "40LD read config failed.\n"); 25708c2ecf20Sopenharmony_ci goto free_pci; 25718c2ecf20Sopenharmony_ci } 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci } 25748c2ecf20Sopenharmony_ci else { 25758c2ecf20Sopenharmony_ci mc.cmd = NEW_READ_CONFIG_8LD; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci if( mega_internal_command(adapter, &mc, NULL) ) { 25788c2ecf20Sopenharmony_ci mc.cmd = READ_CONFIG_8LD; 25798c2ecf20Sopenharmony_ci if( mega_internal_command(adapter, &mc, NULL) ) { 25808c2ecf20Sopenharmony_ci seq_puts(m, "8LD read config failed.\n"); 25818c2ecf20Sopenharmony_ci goto free_pci; 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci for( i = start; i < ( (end+1 < num_ldrv) ? end+1 : num_ldrv ); i++ ) { 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 25898c2ecf20Sopenharmony_ci lparam = 25908c2ecf20Sopenharmony_ci &((disk_array_40ld *)disk_array)->ldrv[i].lparam; 25918c2ecf20Sopenharmony_ci } 25928c2ecf20Sopenharmony_ci else { 25938c2ecf20Sopenharmony_ci lparam = 25948c2ecf20Sopenharmony_ci &((disk_array_8ld *)disk_array)->ldrv[i].lparam; 25958c2ecf20Sopenharmony_ci } 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci /* 25988c2ecf20Sopenharmony_ci * Check for overflow. We print less than 240 characters for 25998c2ecf20Sopenharmony_ci * information about each logical drive. 26008c2ecf20Sopenharmony_ci */ 26018c2ecf20Sopenharmony_ci seq_printf(m, "Logical drive:%2d:, ", i); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci switch( rdrv_state[i] & 0x0F ) { 26048c2ecf20Sopenharmony_ci case RDRV_OFFLINE: 26058c2ecf20Sopenharmony_ci seq_puts(m, "state: offline"); 26068c2ecf20Sopenharmony_ci break; 26078c2ecf20Sopenharmony_ci case RDRV_DEGRADED: 26088c2ecf20Sopenharmony_ci seq_puts(m, "state: degraded"); 26098c2ecf20Sopenharmony_ci break; 26108c2ecf20Sopenharmony_ci case RDRV_OPTIMAL: 26118c2ecf20Sopenharmony_ci seq_puts(m, "state: optimal"); 26128c2ecf20Sopenharmony_ci break; 26138c2ecf20Sopenharmony_ci case RDRV_DELETED: 26148c2ecf20Sopenharmony_ci seq_puts(m, "state: deleted"); 26158c2ecf20Sopenharmony_ci break; 26168c2ecf20Sopenharmony_ci default: 26178c2ecf20Sopenharmony_ci seq_puts(m, "state: unknown"); 26188c2ecf20Sopenharmony_ci break; 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci /* 26228c2ecf20Sopenharmony_ci * Check if check consistency or initialization is going on 26238c2ecf20Sopenharmony_ci * for this logical drive. 26248c2ecf20Sopenharmony_ci */ 26258c2ecf20Sopenharmony_ci if( (rdrv_state[i] & 0xF0) == 0x20 ) 26268c2ecf20Sopenharmony_ci seq_puts(m, ", check-consistency in progress"); 26278c2ecf20Sopenharmony_ci else if( (rdrv_state[i] & 0xF0) == 0x10 ) 26288c2ecf20Sopenharmony_ci seq_puts(m, ", initialization in progress"); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci seq_printf(m, "Span depth:%3d, ", lparam->span_depth); 26338c2ecf20Sopenharmony_ci seq_printf(m, "RAID level:%3d, ", lparam->level); 26348c2ecf20Sopenharmony_ci seq_printf(m, "Stripe size:%3d, ", 26358c2ecf20Sopenharmony_ci lparam->stripe_sz ? lparam->stripe_sz/2: 128); 26368c2ecf20Sopenharmony_ci seq_printf(m, "Row size:%3d\n", lparam->row_size); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci seq_puts(m, "Read Policy: "); 26398c2ecf20Sopenharmony_ci switch(lparam->read_ahead) { 26408c2ecf20Sopenharmony_ci case NO_READ_AHEAD: 26418c2ecf20Sopenharmony_ci seq_puts(m, "No read ahead, "); 26428c2ecf20Sopenharmony_ci break; 26438c2ecf20Sopenharmony_ci case READ_AHEAD: 26448c2ecf20Sopenharmony_ci seq_puts(m, "Read ahead, "); 26458c2ecf20Sopenharmony_ci break; 26468c2ecf20Sopenharmony_ci case ADAP_READ_AHEAD: 26478c2ecf20Sopenharmony_ci seq_puts(m, "Adaptive, "); 26488c2ecf20Sopenharmony_ci break; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci seq_puts(m, "Write Policy: "); 26538c2ecf20Sopenharmony_ci switch(lparam->write_mode) { 26548c2ecf20Sopenharmony_ci case WRMODE_WRITE_THRU: 26558c2ecf20Sopenharmony_ci seq_puts(m, "Write thru, "); 26568c2ecf20Sopenharmony_ci break; 26578c2ecf20Sopenharmony_ci case WRMODE_WRITE_BACK: 26588c2ecf20Sopenharmony_ci seq_puts(m, "Write back, "); 26598c2ecf20Sopenharmony_ci break; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci seq_puts(m, "Cache Policy: "); 26638c2ecf20Sopenharmony_ci switch(lparam->direct_io) { 26648c2ecf20Sopenharmony_ci case CACHED_IO: 26658c2ecf20Sopenharmony_ci seq_puts(m, "Cached IO\n\n"); 26668c2ecf20Sopenharmony_ci break; 26678c2ecf20Sopenharmony_ci case DIRECT_IO: 26688c2ecf20Sopenharmony_ci seq_puts(m, "Direct IO\n\n"); 26698c2ecf20Sopenharmony_ci break; 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci } 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_cifree_pci: 26748c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, array_sz, disk_array, 26758c2ecf20Sopenharmony_ci disk_array_dma_handle); 26768c2ecf20Sopenharmony_cifree_inquiry: 26778c2ecf20Sopenharmony_ci mega_free_inquiry(inquiry, dma_handle, pdev); 26788c2ecf20Sopenharmony_cifree_pdev: 26798c2ecf20Sopenharmony_ci free_local_pdev(pdev); 26808c2ecf20Sopenharmony_ci return 0; 26818c2ecf20Sopenharmony_ci} 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci/** 26848c2ecf20Sopenharmony_ci * proc_show_rdrv_10() 26858c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 26868c2ecf20Sopenharmony_ci * @v: File iterator 26878c2ecf20Sopenharmony_ci * 26888c2ecf20Sopenharmony_ci * Display real time information about the logical drives 0 through 9. 26898c2ecf20Sopenharmony_ci */ 26908c2ecf20Sopenharmony_cistatic int 26918c2ecf20Sopenharmony_ciproc_show_rdrv_10(struct seq_file *m, void *v) 26928c2ecf20Sopenharmony_ci{ 26938c2ecf20Sopenharmony_ci return proc_show_rdrv(m, m->private, 0, 9); 26948c2ecf20Sopenharmony_ci} 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci/** 26988c2ecf20Sopenharmony_ci * proc_show_rdrv_20() 26998c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 27008c2ecf20Sopenharmony_ci * @v: File iterator 27018c2ecf20Sopenharmony_ci * 27028c2ecf20Sopenharmony_ci * Display real time information about the logical drives 0 through 9. 27038c2ecf20Sopenharmony_ci */ 27048c2ecf20Sopenharmony_cistatic int 27058c2ecf20Sopenharmony_ciproc_show_rdrv_20(struct seq_file *m, void *v) 27068c2ecf20Sopenharmony_ci{ 27078c2ecf20Sopenharmony_ci return proc_show_rdrv(m, m->private, 10, 19); 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci/** 27128c2ecf20Sopenharmony_ci * proc_show_rdrv_30() 27138c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 27148c2ecf20Sopenharmony_ci * @v: File iterator 27158c2ecf20Sopenharmony_ci * 27168c2ecf20Sopenharmony_ci * Display real time information about the logical drives 0 through 9. 27178c2ecf20Sopenharmony_ci */ 27188c2ecf20Sopenharmony_cistatic int 27198c2ecf20Sopenharmony_ciproc_show_rdrv_30(struct seq_file *m, void *v) 27208c2ecf20Sopenharmony_ci{ 27218c2ecf20Sopenharmony_ci return proc_show_rdrv(m, m->private, 20, 29); 27228c2ecf20Sopenharmony_ci} 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci/** 27268c2ecf20Sopenharmony_ci * proc_show_rdrv_40() 27278c2ecf20Sopenharmony_ci * @m: Synthetic file construction data 27288c2ecf20Sopenharmony_ci * @v: File iterator 27298c2ecf20Sopenharmony_ci * 27308c2ecf20Sopenharmony_ci * Display real time information about the logical drives 0 through 9. 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_cistatic int 27338c2ecf20Sopenharmony_ciproc_show_rdrv_40(struct seq_file *m, void *v) 27348c2ecf20Sopenharmony_ci{ 27358c2ecf20Sopenharmony_ci return proc_show_rdrv(m, m->private, 30, 39); 27368c2ecf20Sopenharmony_ci} 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci/** 27398c2ecf20Sopenharmony_ci * mega_create_proc_entry() 27408c2ecf20Sopenharmony_ci * @index: index in soft state array 27418c2ecf20Sopenharmony_ci * @parent: parent node for this /proc entry 27428c2ecf20Sopenharmony_ci * 27438c2ecf20Sopenharmony_ci * Creates /proc entries for our controllers. 27448c2ecf20Sopenharmony_ci */ 27458c2ecf20Sopenharmony_cistatic void 27468c2ecf20Sopenharmony_cimega_create_proc_entry(int index, struct proc_dir_entry *parent) 27478c2ecf20Sopenharmony_ci{ 27488c2ecf20Sopenharmony_ci adapter_t *adapter = hba_soft_state[index]; 27498c2ecf20Sopenharmony_ci struct proc_dir_entry *dir; 27508c2ecf20Sopenharmony_ci u8 string[16]; 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci sprintf(string, "hba%d", adapter->host->host_no); 27538c2ecf20Sopenharmony_ci dir = proc_mkdir_data(string, 0, parent, adapter); 27548c2ecf20Sopenharmony_ci if (!dir) { 27558c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "proc_mkdir failed\n"); 27568c2ecf20Sopenharmony_ci return; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci proc_create_single_data("config", S_IRUSR, dir, 27608c2ecf20Sopenharmony_ci proc_show_config, adapter); 27618c2ecf20Sopenharmony_ci proc_create_single_data("stat", S_IRUSR, dir, 27628c2ecf20Sopenharmony_ci proc_show_stat, adapter); 27638c2ecf20Sopenharmony_ci proc_create_single_data("mailbox", S_IRUSR, dir, 27648c2ecf20Sopenharmony_ci proc_show_mbox, adapter); 27658c2ecf20Sopenharmony_ci#if MEGA_HAVE_ENH_PROC 27668c2ecf20Sopenharmony_ci proc_create_single_data("rebuild-rate", S_IRUSR, dir, 27678c2ecf20Sopenharmony_ci proc_show_rebuild_rate, adapter); 27688c2ecf20Sopenharmony_ci proc_create_single_data("battery-status", S_IRUSR, dir, 27698c2ecf20Sopenharmony_ci proc_show_battery, adapter); 27708c2ecf20Sopenharmony_ci proc_create_single_data("diskdrives-ch0", S_IRUSR, dir, 27718c2ecf20Sopenharmony_ci proc_show_pdrv_ch0, adapter); 27728c2ecf20Sopenharmony_ci proc_create_single_data("diskdrives-ch1", S_IRUSR, dir, 27738c2ecf20Sopenharmony_ci proc_show_pdrv_ch1, adapter); 27748c2ecf20Sopenharmony_ci proc_create_single_data("diskdrives-ch2", S_IRUSR, dir, 27758c2ecf20Sopenharmony_ci proc_show_pdrv_ch2, adapter); 27768c2ecf20Sopenharmony_ci proc_create_single_data("diskdrives-ch3", S_IRUSR, dir, 27778c2ecf20Sopenharmony_ci proc_show_pdrv_ch3, adapter); 27788c2ecf20Sopenharmony_ci proc_create_single_data("raiddrives-0-9", S_IRUSR, dir, 27798c2ecf20Sopenharmony_ci proc_show_rdrv_10, adapter); 27808c2ecf20Sopenharmony_ci proc_create_single_data("raiddrives-10-19", S_IRUSR, dir, 27818c2ecf20Sopenharmony_ci proc_show_rdrv_20, adapter); 27828c2ecf20Sopenharmony_ci proc_create_single_data("raiddrives-20-29", S_IRUSR, dir, 27838c2ecf20Sopenharmony_ci proc_show_rdrv_30, adapter); 27848c2ecf20Sopenharmony_ci proc_create_single_data("raiddrives-30-39", S_IRUSR, dir, 27858c2ecf20Sopenharmony_ci proc_show_rdrv_40, adapter); 27868c2ecf20Sopenharmony_ci#endif 27878c2ecf20Sopenharmony_ci} 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci#else 27908c2ecf20Sopenharmony_cistatic inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent) 27918c2ecf20Sopenharmony_ci{ 27928c2ecf20Sopenharmony_ci} 27938c2ecf20Sopenharmony_ci#endif 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci/* 27978c2ecf20Sopenharmony_ci * megaraid_biosparam() 27988c2ecf20Sopenharmony_ci * 27998c2ecf20Sopenharmony_ci * Return the disk geometry for a particular disk 28008c2ecf20Sopenharmony_ci */ 28018c2ecf20Sopenharmony_cistatic int 28028c2ecf20Sopenharmony_cimegaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, 28038c2ecf20Sopenharmony_ci sector_t capacity, int geom[]) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci adapter_t *adapter; 28068c2ecf20Sopenharmony_ci int heads; 28078c2ecf20Sopenharmony_ci int sectors; 28088c2ecf20Sopenharmony_ci int cylinders; 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci /* Get pointer to host config structure */ 28118c2ecf20Sopenharmony_ci adapter = (adapter_t *)sdev->host->hostdata; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci if (IS_RAID_CH(adapter, sdev->channel)) { 28148c2ecf20Sopenharmony_ci /* Default heads (64) & sectors (32) */ 28158c2ecf20Sopenharmony_ci heads = 64; 28168c2ecf20Sopenharmony_ci sectors = 32; 28178c2ecf20Sopenharmony_ci cylinders = (ulong)capacity / (heads * sectors); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci /* 28208c2ecf20Sopenharmony_ci * Handle extended translation size for logical drives 28218c2ecf20Sopenharmony_ci * > 1Gb 28228c2ecf20Sopenharmony_ci */ 28238c2ecf20Sopenharmony_ci if ((ulong)capacity >= 0x200000) { 28248c2ecf20Sopenharmony_ci heads = 255; 28258c2ecf20Sopenharmony_ci sectors = 63; 28268c2ecf20Sopenharmony_ci cylinders = (ulong)capacity / (heads * sectors); 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci /* return result */ 28308c2ecf20Sopenharmony_ci geom[0] = heads; 28318c2ecf20Sopenharmony_ci geom[1] = sectors; 28328c2ecf20Sopenharmony_ci geom[2] = cylinders; 28338c2ecf20Sopenharmony_ci } 28348c2ecf20Sopenharmony_ci else { 28358c2ecf20Sopenharmony_ci if (scsi_partsize(bdev, capacity, geom)) 28368c2ecf20Sopenharmony_ci return 0; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci dev_info(&adapter->dev->dev, 28398c2ecf20Sopenharmony_ci "invalid partition on this disk on channel %d\n", 28408c2ecf20Sopenharmony_ci sdev->channel); 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci /* Default heads (64) & sectors (32) */ 28438c2ecf20Sopenharmony_ci heads = 64; 28448c2ecf20Sopenharmony_ci sectors = 32; 28458c2ecf20Sopenharmony_ci cylinders = (ulong)capacity / (heads * sectors); 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci /* Handle extended translation size for logical drives > 1Gb */ 28488c2ecf20Sopenharmony_ci if ((ulong)capacity >= 0x200000) { 28498c2ecf20Sopenharmony_ci heads = 255; 28508c2ecf20Sopenharmony_ci sectors = 63; 28518c2ecf20Sopenharmony_ci cylinders = (ulong)capacity / (heads * sectors); 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci /* return result */ 28558c2ecf20Sopenharmony_ci geom[0] = heads; 28568c2ecf20Sopenharmony_ci geom[1] = sectors; 28578c2ecf20Sopenharmony_ci geom[2] = cylinders; 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci return 0; 28618c2ecf20Sopenharmony_ci} 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci/** 28648c2ecf20Sopenharmony_ci * mega_init_scb() 28658c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 28668c2ecf20Sopenharmony_ci * 28678c2ecf20Sopenharmony_ci * Allocate memory for the various pointers in the scb structures: 28688c2ecf20Sopenharmony_ci * scatter-gather list pointer, passthru and extended passthru structure 28698c2ecf20Sopenharmony_ci * pointers. 28708c2ecf20Sopenharmony_ci */ 28718c2ecf20Sopenharmony_cistatic int 28728c2ecf20Sopenharmony_cimega_init_scb(adapter_t *adapter) 28738c2ecf20Sopenharmony_ci{ 28748c2ecf20Sopenharmony_ci scb_t *scb; 28758c2ecf20Sopenharmony_ci int i; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci for( i = 0; i < adapter->max_cmds; i++ ) { 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci scb = &adapter->scb_list[i]; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci scb->sgl64 = NULL; 28828c2ecf20Sopenharmony_ci scb->sgl = NULL; 28838c2ecf20Sopenharmony_ci scb->pthru = NULL; 28848c2ecf20Sopenharmony_ci scb->epthru = NULL; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci for( i = 0; i < adapter->max_cmds; i++ ) { 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci scb = &adapter->scb_list[i]; 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci scb->idx = i; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci scb->sgl64 = dma_alloc_coherent(&adapter->dev->dev, 28948c2ecf20Sopenharmony_ci sizeof(mega_sgl64) * adapter->sglen, 28958c2ecf20Sopenharmony_ci &scb->sgl_dma_addr, GFP_KERNEL); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci scb->sgl = (mega_sglist *)scb->sgl64; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci if( !scb->sgl ) { 29008c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "RAID: Can't allocate sglist\n"); 29018c2ecf20Sopenharmony_ci mega_free_sgl(adapter); 29028c2ecf20Sopenharmony_ci return -1; 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci scb->pthru = dma_alloc_coherent(&adapter->dev->dev, 29068c2ecf20Sopenharmony_ci sizeof(mega_passthru), 29078c2ecf20Sopenharmony_ci &scb->pthru_dma_addr, GFP_KERNEL); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci if( !scb->pthru ) { 29108c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "RAID: Can't allocate passthru\n"); 29118c2ecf20Sopenharmony_ci mega_free_sgl(adapter); 29128c2ecf20Sopenharmony_ci return -1; 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci scb->epthru = dma_alloc_coherent(&adapter->dev->dev, 29168c2ecf20Sopenharmony_ci sizeof(mega_ext_passthru), 29178c2ecf20Sopenharmony_ci &scb->epthru_dma_addr, GFP_KERNEL); 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if( !scb->epthru ) { 29208c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, 29218c2ecf20Sopenharmony_ci "Can't allocate extended passthru\n"); 29228c2ecf20Sopenharmony_ci mega_free_sgl(adapter); 29238c2ecf20Sopenharmony_ci return -1; 29248c2ecf20Sopenharmony_ci } 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci scb->dma_type = MEGA_DMA_TYPE_NONE; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci /* 29308c2ecf20Sopenharmony_ci * Link to free list 29318c2ecf20Sopenharmony_ci * lock not required since we are loading the driver, so no 29328c2ecf20Sopenharmony_ci * commands possible right now. 29338c2ecf20Sopenharmony_ci */ 29348c2ecf20Sopenharmony_ci scb->state = SCB_FREE; 29358c2ecf20Sopenharmony_ci scb->cmd = NULL; 29368c2ecf20Sopenharmony_ci list_add(&scb->list, &adapter->free_list); 29378c2ecf20Sopenharmony_ci } 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci return 0; 29408c2ecf20Sopenharmony_ci} 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci/** 29448c2ecf20Sopenharmony_ci * megadev_open() 29458c2ecf20Sopenharmony_ci * @inode: unused 29468c2ecf20Sopenharmony_ci * @filep: unused 29478c2ecf20Sopenharmony_ci * 29488c2ecf20Sopenharmony_ci * Routines for the character/ioctl interface to the driver. Find out if this 29498c2ecf20Sopenharmony_ci * is a valid open. 29508c2ecf20Sopenharmony_ci */ 29518c2ecf20Sopenharmony_cistatic int 29528c2ecf20Sopenharmony_cimegadev_open (struct inode *inode, struct file *filep) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci /* 29558c2ecf20Sopenharmony_ci * Only allow superuser to access private ioctl interface 29568c2ecf20Sopenharmony_ci */ 29578c2ecf20Sopenharmony_ci if( !capable(CAP_SYS_ADMIN) ) return -EACCES; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci return 0; 29608c2ecf20Sopenharmony_ci} 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci/** 29648c2ecf20Sopenharmony_ci * megadev_ioctl() 29658c2ecf20Sopenharmony_ci * @filep: Our device file 29668c2ecf20Sopenharmony_ci * @cmd: ioctl command 29678c2ecf20Sopenharmony_ci * @arg: user buffer 29688c2ecf20Sopenharmony_ci * 29698c2ecf20Sopenharmony_ci * ioctl entry point for our private ioctl interface. We move the data in from 29708c2ecf20Sopenharmony_ci * the user space, prepare the command (if necessary, convert the old MIMD 29718c2ecf20Sopenharmony_ci * ioctl to new ioctl command), and issue a synchronous command to the 29728c2ecf20Sopenharmony_ci * controller. 29738c2ecf20Sopenharmony_ci */ 29748c2ecf20Sopenharmony_cistatic int 29758c2ecf20Sopenharmony_cimegadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) 29768c2ecf20Sopenharmony_ci{ 29778c2ecf20Sopenharmony_ci adapter_t *adapter; 29788c2ecf20Sopenharmony_ci nitioctl_t uioc; 29798c2ecf20Sopenharmony_ci int adapno; 29808c2ecf20Sopenharmony_ci int rval; 29818c2ecf20Sopenharmony_ci mega_passthru __user *upthru; /* user address for passthru */ 29828c2ecf20Sopenharmony_ci mega_passthru *pthru; /* copy user passthru here */ 29838c2ecf20Sopenharmony_ci dma_addr_t pthru_dma_hndl; 29848c2ecf20Sopenharmony_ci void *data = NULL; /* data to be transferred */ 29858c2ecf20Sopenharmony_ci dma_addr_t data_dma_hndl; /* dma handle for data xfer area */ 29868c2ecf20Sopenharmony_ci megacmd_t mc; 29878c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 29888c2ecf20Sopenharmony_ci megastat_t __user *ustats = NULL; 29898c2ecf20Sopenharmony_ci int num_ldrv = 0; 29908c2ecf20Sopenharmony_ci#endif 29918c2ecf20Sopenharmony_ci u32 uxferaddr = 0; 29928c2ecf20Sopenharmony_ci struct pci_dev *pdev; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci /* 29958c2ecf20Sopenharmony_ci * Make sure only USCSICMD are issued through this interface. 29968c2ecf20Sopenharmony_ci * MIMD application would still fire different command. 29978c2ecf20Sopenharmony_ci */ 29988c2ecf20Sopenharmony_ci if( (_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD) ) { 29998c2ecf20Sopenharmony_ci return -EINVAL; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci /* 30038c2ecf20Sopenharmony_ci * Check and convert a possible MIMD command to NIT command. 30048c2ecf20Sopenharmony_ci * mega_m_to_n() copies the data from the user space, so we do not 30058c2ecf20Sopenharmony_ci * have to do it here. 30068c2ecf20Sopenharmony_ci * NOTE: We will need some user address to copyout the data, therefore 30078c2ecf20Sopenharmony_ci * the inteface layer will also provide us with the required user 30088c2ecf20Sopenharmony_ci * addresses. 30098c2ecf20Sopenharmony_ci */ 30108c2ecf20Sopenharmony_ci memset(&uioc, 0, sizeof(nitioctl_t)); 30118c2ecf20Sopenharmony_ci if( (rval = mega_m_to_n( (void __user *)arg, &uioc)) != 0 ) 30128c2ecf20Sopenharmony_ci return rval; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci switch( uioc.opcode ) { 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci case GET_DRIVER_VER: 30188c2ecf20Sopenharmony_ci if( put_user(driver_ver, (u32 __user *)uioc.uioc_uaddr) ) 30198c2ecf20Sopenharmony_ci return (-EFAULT); 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci break; 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci case GET_N_ADAP: 30248c2ecf20Sopenharmony_ci if( put_user(hba_count, (u32 __user *)uioc.uioc_uaddr) ) 30258c2ecf20Sopenharmony_ci return (-EFAULT); 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci /* 30288c2ecf20Sopenharmony_ci * Shucks. MIMD interface returns a positive value for number 30298c2ecf20Sopenharmony_ci * of adapters. TODO: Change it to return 0 when there is no 30308c2ecf20Sopenharmony_ci * applicatio using mimd interface. 30318c2ecf20Sopenharmony_ci */ 30328c2ecf20Sopenharmony_ci return hba_count; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci case GET_ADAP_INFO: 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci /* 30378c2ecf20Sopenharmony_ci * Which adapter 30388c2ecf20Sopenharmony_ci */ 30398c2ecf20Sopenharmony_ci if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) 30408c2ecf20Sopenharmony_ci return (-ENODEV); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if( copy_to_user(uioc.uioc_uaddr, mcontroller+adapno, 30438c2ecf20Sopenharmony_ci sizeof(struct mcontroller)) ) 30448c2ecf20Sopenharmony_ci return (-EFAULT); 30458c2ecf20Sopenharmony_ci break; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci#if MEGA_HAVE_STATS 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci case GET_STATS: 30508c2ecf20Sopenharmony_ci /* 30518c2ecf20Sopenharmony_ci * Which adapter 30528c2ecf20Sopenharmony_ci */ 30538c2ecf20Sopenharmony_ci if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) 30548c2ecf20Sopenharmony_ci return (-ENODEV); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci adapter = hba_soft_state[adapno]; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci ustats = uioc.uioc_uaddr; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) ) 30618c2ecf20Sopenharmony_ci return (-EFAULT); 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci /* 30648c2ecf20Sopenharmony_ci * Check for the validity of the logical drive number 30658c2ecf20Sopenharmony_ci */ 30668c2ecf20Sopenharmony_ci if( num_ldrv >= MAX_LOGICAL_DRIVES_40LD ) return -EINVAL; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if( copy_to_user(ustats->nreads, adapter->nreads, 30698c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30708c2ecf20Sopenharmony_ci return -EFAULT; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci if( copy_to_user(ustats->nreadblocks, adapter->nreadblocks, 30738c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30748c2ecf20Sopenharmony_ci return -EFAULT; 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci if( copy_to_user(ustats->nwrites, adapter->nwrites, 30778c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30788c2ecf20Sopenharmony_ci return -EFAULT; 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci if( copy_to_user(ustats->nwriteblocks, adapter->nwriteblocks, 30818c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30828c2ecf20Sopenharmony_ci return -EFAULT; 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci if( copy_to_user(ustats->rd_errors, adapter->rd_errors, 30858c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30868c2ecf20Sopenharmony_ci return -EFAULT; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci if( copy_to_user(ustats->wr_errors, adapter->wr_errors, 30898c2ecf20Sopenharmony_ci num_ldrv*sizeof(u32)) ) 30908c2ecf20Sopenharmony_ci return -EFAULT; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci return 0; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci#endif 30958c2ecf20Sopenharmony_ci case MBOX_CMD: 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci /* 30988c2ecf20Sopenharmony_ci * Which adapter 30998c2ecf20Sopenharmony_ci */ 31008c2ecf20Sopenharmony_ci if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) 31018c2ecf20Sopenharmony_ci return (-ENODEV); 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci adapter = hba_soft_state[adapno]; 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci /* 31068c2ecf20Sopenharmony_ci * Deletion of logical drive is a special case. The adapter 31078c2ecf20Sopenharmony_ci * should be quiescent before this command is issued. 31088c2ecf20Sopenharmony_ci */ 31098c2ecf20Sopenharmony_ci if( uioc.uioc_rmbox[0] == FC_DEL_LOGDRV && 31108c2ecf20Sopenharmony_ci uioc.uioc_rmbox[2] == OP_DEL_LOGDRV ) { 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci /* 31138c2ecf20Sopenharmony_ci * Do we support this feature 31148c2ecf20Sopenharmony_ci */ 31158c2ecf20Sopenharmony_ci if( !adapter->support_random_del ) { 31168c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "logdrv " 31178c2ecf20Sopenharmony_ci "delete on non-supporting F/W\n"); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci return (-EINVAL); 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci rval = mega_del_logdrv( adapter, uioc.uioc_rmbox[3] ); 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci if( rval == 0 ) { 31258c2ecf20Sopenharmony_ci memset(&mc, 0, sizeof(megacmd_t)); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci mc.status = rval; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci rval = mega_n_to_m((void __user *)arg, &mc); 31308c2ecf20Sopenharmony_ci } 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci return rval; 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci /* 31358c2ecf20Sopenharmony_ci * This interface only support the regular passthru commands. 31368c2ecf20Sopenharmony_ci * Reject extended passthru and 64-bit passthru 31378c2ecf20Sopenharmony_ci */ 31388c2ecf20Sopenharmony_ci if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU64 || 31398c2ecf20Sopenharmony_ci uioc.uioc_rmbox[0] == MEGA_MBOXCMD_EXTPTHRU ) { 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "rejected passthru\n"); 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci return (-EINVAL); 31448c2ecf20Sopenharmony_ci } 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci /* 31478c2ecf20Sopenharmony_ci * For all internal commands, the buffer must be allocated in 31488c2ecf20Sopenharmony_ci * <4GB address range 31498c2ecf20Sopenharmony_ci */ 31508c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) 31518c2ecf20Sopenharmony_ci return -EIO; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci /* Is it a passthru command or a DCMD */ 31548c2ecf20Sopenharmony_ci if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU ) { 31558c2ecf20Sopenharmony_ci /* Passthru commands */ 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci pthru = dma_alloc_coherent(&pdev->dev, 31588c2ecf20Sopenharmony_ci sizeof(mega_passthru), 31598c2ecf20Sopenharmony_ci &pthru_dma_hndl, GFP_KERNEL); 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci if( pthru == NULL ) { 31628c2ecf20Sopenharmony_ci free_local_pdev(pdev); 31638c2ecf20Sopenharmony_ci return (-ENOMEM); 31648c2ecf20Sopenharmony_ci } 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci /* 31678c2ecf20Sopenharmony_ci * The user passthru structure 31688c2ecf20Sopenharmony_ci */ 31698c2ecf20Sopenharmony_ci upthru = (mega_passthru __user *)(unsigned long)MBOX(uioc)->xferaddr; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci /* 31728c2ecf20Sopenharmony_ci * Copy in the user passthru here. 31738c2ecf20Sopenharmony_ci */ 31748c2ecf20Sopenharmony_ci if( copy_from_user(pthru, upthru, 31758c2ecf20Sopenharmony_ci sizeof(mega_passthru)) ) { 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 31788c2ecf20Sopenharmony_ci sizeof(mega_passthru), 31798c2ecf20Sopenharmony_ci pthru, pthru_dma_hndl); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci free_local_pdev(pdev); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci return (-EFAULT); 31848c2ecf20Sopenharmony_ci } 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci /* 31878c2ecf20Sopenharmony_ci * Is there a data transfer 31888c2ecf20Sopenharmony_ci */ 31898c2ecf20Sopenharmony_ci if( pthru->dataxferlen ) { 31908c2ecf20Sopenharmony_ci data = dma_alloc_coherent(&pdev->dev, 31918c2ecf20Sopenharmony_ci pthru->dataxferlen, 31928c2ecf20Sopenharmony_ci &data_dma_hndl, 31938c2ecf20Sopenharmony_ci GFP_KERNEL); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci if( data == NULL ) { 31968c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 31978c2ecf20Sopenharmony_ci sizeof(mega_passthru), 31988c2ecf20Sopenharmony_ci pthru, 31998c2ecf20Sopenharmony_ci pthru_dma_hndl); 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci free_local_pdev(pdev); 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci return (-ENOMEM); 32048c2ecf20Sopenharmony_ci } 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci /* 32078c2ecf20Sopenharmony_ci * Save the user address and point the kernel 32088c2ecf20Sopenharmony_ci * address at just allocated memory 32098c2ecf20Sopenharmony_ci */ 32108c2ecf20Sopenharmony_ci uxferaddr = pthru->dataxferaddr; 32118c2ecf20Sopenharmony_ci pthru->dataxferaddr = data_dma_hndl; 32128c2ecf20Sopenharmony_ci } 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci /* 32168c2ecf20Sopenharmony_ci * Is data coming down-stream 32178c2ecf20Sopenharmony_ci */ 32188c2ecf20Sopenharmony_ci if( pthru->dataxferlen && (uioc.flags & UIOC_WR) ) { 32198c2ecf20Sopenharmony_ci /* 32208c2ecf20Sopenharmony_ci * Get the user data 32218c2ecf20Sopenharmony_ci */ 32228c2ecf20Sopenharmony_ci if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr, 32238c2ecf20Sopenharmony_ci pthru->dataxferlen) ) { 32248c2ecf20Sopenharmony_ci rval = (-EFAULT); 32258c2ecf20Sopenharmony_ci goto freemem_and_return; 32268c2ecf20Sopenharmony_ci } 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci memset(&mc, 0, sizeof(megacmd_t)); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci mc.cmd = MEGA_MBOXCMD_PASSTHRU; 32328c2ecf20Sopenharmony_ci mc.xferaddr = (u32)pthru_dma_hndl; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci /* 32358c2ecf20Sopenharmony_ci * Issue the command 32368c2ecf20Sopenharmony_ci */ 32378c2ecf20Sopenharmony_ci mega_internal_command(adapter, &mc, pthru); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci rval = mega_n_to_m((void __user *)arg, &mc); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci if( rval ) goto freemem_and_return; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci /* 32458c2ecf20Sopenharmony_ci * Is data going up-stream 32468c2ecf20Sopenharmony_ci */ 32478c2ecf20Sopenharmony_ci if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) { 32488c2ecf20Sopenharmony_ci if( copy_to_user((char __user *)(unsigned long) uxferaddr, data, 32498c2ecf20Sopenharmony_ci pthru->dataxferlen) ) { 32508c2ecf20Sopenharmony_ci rval = (-EFAULT); 32518c2ecf20Sopenharmony_ci } 32528c2ecf20Sopenharmony_ci } 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci /* 32558c2ecf20Sopenharmony_ci * Send the request sense data also, irrespective of 32568c2ecf20Sopenharmony_ci * whether the user has asked for it or not. 32578c2ecf20Sopenharmony_ci */ 32588c2ecf20Sopenharmony_ci if (copy_to_user(upthru->reqsensearea, 32598c2ecf20Sopenharmony_ci pthru->reqsensearea, 14)) 32608c2ecf20Sopenharmony_ci rval = -EFAULT; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_cifreemem_and_return: 32638c2ecf20Sopenharmony_ci if( pthru->dataxferlen ) { 32648c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 32658c2ecf20Sopenharmony_ci pthru->dataxferlen, data, 32668c2ecf20Sopenharmony_ci data_dma_hndl); 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(mega_passthru), 32708c2ecf20Sopenharmony_ci pthru, pthru_dma_hndl); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci free_local_pdev(pdev); 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci return rval; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci else { 32778c2ecf20Sopenharmony_ci /* DCMD commands */ 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci /* 32808c2ecf20Sopenharmony_ci * Is there a data transfer 32818c2ecf20Sopenharmony_ci */ 32828c2ecf20Sopenharmony_ci if( uioc.xferlen ) { 32838c2ecf20Sopenharmony_ci data = dma_alloc_coherent(&pdev->dev, 32848c2ecf20Sopenharmony_ci uioc.xferlen, 32858c2ecf20Sopenharmony_ci &data_dma_hndl, 32868c2ecf20Sopenharmony_ci GFP_KERNEL); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci if( data == NULL ) { 32898c2ecf20Sopenharmony_ci free_local_pdev(pdev); 32908c2ecf20Sopenharmony_ci return (-ENOMEM); 32918c2ecf20Sopenharmony_ci } 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci uxferaddr = MBOX(uioc)->xferaddr; 32948c2ecf20Sopenharmony_ci } 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci /* 32978c2ecf20Sopenharmony_ci * Is data coming down-stream 32988c2ecf20Sopenharmony_ci */ 32998c2ecf20Sopenharmony_ci if( uioc.xferlen && (uioc.flags & UIOC_WR) ) { 33008c2ecf20Sopenharmony_ci /* 33018c2ecf20Sopenharmony_ci * Get the user data 33028c2ecf20Sopenharmony_ci */ 33038c2ecf20Sopenharmony_ci if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr, 33048c2ecf20Sopenharmony_ci uioc.xferlen) ) { 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 33078c2ecf20Sopenharmony_ci uioc.xferlen, data, 33088c2ecf20Sopenharmony_ci data_dma_hndl); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci free_local_pdev(pdev); 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci return (-EFAULT); 33138c2ecf20Sopenharmony_ci } 33148c2ecf20Sopenharmony_ci } 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci memcpy(&mc, MBOX(uioc), sizeof(megacmd_t)); 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci mc.xferaddr = (u32)data_dma_hndl; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci /* 33218c2ecf20Sopenharmony_ci * Issue the command 33228c2ecf20Sopenharmony_ci */ 33238c2ecf20Sopenharmony_ci mega_internal_command(adapter, &mc, NULL); 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci rval = mega_n_to_m((void __user *)arg, &mc); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci if( rval ) { 33288c2ecf20Sopenharmony_ci if( uioc.xferlen ) { 33298c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 33308c2ecf20Sopenharmony_ci uioc.xferlen, data, 33318c2ecf20Sopenharmony_ci data_dma_hndl); 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci free_local_pdev(pdev); 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci return rval; 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci /* 33408c2ecf20Sopenharmony_ci * Is data going up-stream 33418c2ecf20Sopenharmony_ci */ 33428c2ecf20Sopenharmony_ci if( uioc.xferlen && (uioc.flags & UIOC_RD) ) { 33438c2ecf20Sopenharmony_ci if( copy_to_user((char __user *)(unsigned long) uxferaddr, data, 33448c2ecf20Sopenharmony_ci uioc.xferlen) ) { 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci rval = (-EFAULT); 33478c2ecf20Sopenharmony_ci } 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci if( uioc.xferlen ) { 33518c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, uioc.xferlen, 33528c2ecf20Sopenharmony_ci data, data_dma_hndl); 33538c2ecf20Sopenharmony_ci } 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci free_local_pdev(pdev); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci return rval; 33588c2ecf20Sopenharmony_ci } 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci default: 33618c2ecf20Sopenharmony_ci return (-EINVAL); 33628c2ecf20Sopenharmony_ci } 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci return 0; 33658c2ecf20Sopenharmony_ci} 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_cistatic long 33688c2ecf20Sopenharmony_cimegadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) 33698c2ecf20Sopenharmony_ci{ 33708c2ecf20Sopenharmony_ci int ret; 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_ci mutex_lock(&megadev_mutex); 33738c2ecf20Sopenharmony_ci ret = megadev_ioctl(filep, cmd, arg); 33748c2ecf20Sopenharmony_ci mutex_unlock(&megadev_mutex); 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci return ret; 33778c2ecf20Sopenharmony_ci} 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci/** 33808c2ecf20Sopenharmony_ci * mega_m_to_n() 33818c2ecf20Sopenharmony_ci * @arg: user address 33828c2ecf20Sopenharmony_ci * @uioc: new ioctl structure 33838c2ecf20Sopenharmony_ci * 33848c2ecf20Sopenharmony_ci * A thin layer to convert older mimd interface ioctl structure to NIT ioctl 33858c2ecf20Sopenharmony_ci * structure 33868c2ecf20Sopenharmony_ci * 33878c2ecf20Sopenharmony_ci * Converts the older mimd ioctl structure to newer NIT structure 33888c2ecf20Sopenharmony_ci */ 33898c2ecf20Sopenharmony_cistatic int 33908c2ecf20Sopenharmony_cimega_m_to_n(void __user *arg, nitioctl_t *uioc) 33918c2ecf20Sopenharmony_ci{ 33928c2ecf20Sopenharmony_ci struct uioctl_t uioc_mimd; 33938c2ecf20Sopenharmony_ci char signature[8] = {0}; 33948c2ecf20Sopenharmony_ci u8 opcode; 33958c2ecf20Sopenharmony_ci u8 subopcode; 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci /* 33998c2ecf20Sopenharmony_ci * check is the application conforms to NIT. We do not have to do much 34008c2ecf20Sopenharmony_ci * in that case. 34018c2ecf20Sopenharmony_ci * We exploit the fact that the signature is stored in the very 34028c2ecf20Sopenharmony_ci * beginning of the structure. 34038c2ecf20Sopenharmony_ci */ 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci if( copy_from_user(signature, arg, 7) ) 34068c2ecf20Sopenharmony_ci return (-EFAULT); 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci if( memcmp(signature, "MEGANIT", 7) == 0 ) { 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci /* 34118c2ecf20Sopenharmony_ci * NOTE NOTE: The nit ioctl is still under flux because of 34128c2ecf20Sopenharmony_ci * change of mailbox definition, in HPE. No applications yet 34138c2ecf20Sopenharmony_ci * use this interface and let's not have applications use this 34148c2ecf20Sopenharmony_ci * interface till the new specifitions are in place. 34158c2ecf20Sopenharmony_ci */ 34168c2ecf20Sopenharmony_ci return -EINVAL; 34178c2ecf20Sopenharmony_ci#if 0 34188c2ecf20Sopenharmony_ci if( copy_from_user(uioc, arg, sizeof(nitioctl_t)) ) 34198c2ecf20Sopenharmony_ci return (-EFAULT); 34208c2ecf20Sopenharmony_ci return 0; 34218c2ecf20Sopenharmony_ci#endif 34228c2ecf20Sopenharmony_ci } 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_ci /* 34258c2ecf20Sopenharmony_ci * Else assume we have mimd uioctl_t as arg. Convert to nitioctl_t 34268c2ecf20Sopenharmony_ci * 34278c2ecf20Sopenharmony_ci * Get the user ioctl structure 34288c2ecf20Sopenharmony_ci */ 34298c2ecf20Sopenharmony_ci if( copy_from_user(&uioc_mimd, arg, sizeof(struct uioctl_t)) ) 34308c2ecf20Sopenharmony_ci return (-EFAULT); 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci /* 34348c2ecf20Sopenharmony_ci * Get the opcode and subopcode for the commands 34358c2ecf20Sopenharmony_ci */ 34368c2ecf20Sopenharmony_ci opcode = uioc_mimd.ui.fcs.opcode; 34378c2ecf20Sopenharmony_ci subopcode = uioc_mimd.ui.fcs.subopcode; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci switch (opcode) { 34408c2ecf20Sopenharmony_ci case 0x82: 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci switch (subopcode) { 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci case MEGAIOC_QDRVRVER: /* Query driver version */ 34458c2ecf20Sopenharmony_ci uioc->opcode = GET_DRIVER_VER; 34468c2ecf20Sopenharmony_ci uioc->uioc_uaddr = uioc_mimd.data; 34478c2ecf20Sopenharmony_ci break; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci case MEGAIOC_QNADAP: /* Get # of adapters */ 34508c2ecf20Sopenharmony_ci uioc->opcode = GET_N_ADAP; 34518c2ecf20Sopenharmony_ci uioc->uioc_uaddr = uioc_mimd.data; 34528c2ecf20Sopenharmony_ci break; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci case MEGAIOC_QADAPINFO: /* Get adapter information */ 34558c2ecf20Sopenharmony_ci uioc->opcode = GET_ADAP_INFO; 34568c2ecf20Sopenharmony_ci uioc->adapno = uioc_mimd.ui.fcs.adapno; 34578c2ecf20Sopenharmony_ci uioc->uioc_uaddr = uioc_mimd.data; 34588c2ecf20Sopenharmony_ci break; 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci default: 34618c2ecf20Sopenharmony_ci return(-EINVAL); 34628c2ecf20Sopenharmony_ci } 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci break; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci case 0x81: 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci uioc->opcode = MBOX_CMD; 34708c2ecf20Sopenharmony_ci uioc->adapno = uioc_mimd.ui.fcs.adapno; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci uioc->xferlen = uioc_mimd.ui.fcs.length; 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci if( uioc_mimd.outlen ) uioc->flags = UIOC_RD; 34778c2ecf20Sopenharmony_ci if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR; 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci break; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci case 0x80: 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci uioc->opcode = MBOX_CMD; 34848c2ecf20Sopenharmony_ci uioc->adapno = uioc_mimd.ui.fcs.adapno; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18); 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci /* 34898c2ecf20Sopenharmony_ci * Choose the xferlen bigger of input and output data 34908c2ecf20Sopenharmony_ci */ 34918c2ecf20Sopenharmony_ci uioc->xferlen = uioc_mimd.outlen > uioc_mimd.inlen ? 34928c2ecf20Sopenharmony_ci uioc_mimd.outlen : uioc_mimd.inlen; 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci if( uioc_mimd.outlen ) uioc->flags = UIOC_RD; 34958c2ecf20Sopenharmony_ci if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci break; 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci default: 35008c2ecf20Sopenharmony_ci return (-EINVAL); 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci } 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci return 0; 35058c2ecf20Sopenharmony_ci} 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci/* 35088c2ecf20Sopenharmony_ci * mega_n_to_m() 35098c2ecf20Sopenharmony_ci * @arg: user address 35108c2ecf20Sopenharmony_ci * @mc: mailbox command 35118c2ecf20Sopenharmony_ci * 35128c2ecf20Sopenharmony_ci * Updates the status information to the application, depending on application 35138c2ecf20Sopenharmony_ci * conforms to older mimd ioctl interface or newer NIT ioctl interface 35148c2ecf20Sopenharmony_ci */ 35158c2ecf20Sopenharmony_cistatic int 35168c2ecf20Sopenharmony_cimega_n_to_m(void __user *arg, megacmd_t *mc) 35178c2ecf20Sopenharmony_ci{ 35188c2ecf20Sopenharmony_ci nitioctl_t __user *uiocp; 35198c2ecf20Sopenharmony_ci megacmd_t __user *umc; 35208c2ecf20Sopenharmony_ci mega_passthru __user *upthru; 35218c2ecf20Sopenharmony_ci struct uioctl_t __user *uioc_mimd; 35228c2ecf20Sopenharmony_ci char signature[8] = {0}; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci /* 35258c2ecf20Sopenharmony_ci * check is the application conforms to NIT. 35268c2ecf20Sopenharmony_ci */ 35278c2ecf20Sopenharmony_ci if( copy_from_user(signature, arg, 7) ) 35288c2ecf20Sopenharmony_ci return -EFAULT; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci if( memcmp(signature, "MEGANIT", 7) == 0 ) { 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci uiocp = arg; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci if( put_user(mc->status, (u8 __user *)&MBOX_P(uiocp)->status) ) 35358c2ecf20Sopenharmony_ci return (-EFAULT); 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci umc = MBOX_P(uiocp); 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) 35428c2ecf20Sopenharmony_ci return -EFAULT; 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci if( put_user(mc->status, (u8 __user *)&upthru->scsistatus)) 35458c2ecf20Sopenharmony_ci return (-EFAULT); 35468c2ecf20Sopenharmony_ci } 35478c2ecf20Sopenharmony_ci } 35488c2ecf20Sopenharmony_ci else { 35498c2ecf20Sopenharmony_ci uioc_mimd = arg; 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci if( put_user(mc->status, (u8 __user *)&uioc_mimd->mbox[17]) ) 35528c2ecf20Sopenharmony_ci return (-EFAULT); 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci umc = (megacmd_t __user *)uioc_mimd->mbox; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) 35598c2ecf20Sopenharmony_ci return (-EFAULT); 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci if( put_user(mc->status, (u8 __user *)&upthru->scsistatus) ) 35628c2ecf20Sopenharmony_ci return (-EFAULT); 35638c2ecf20Sopenharmony_ci } 35648c2ecf20Sopenharmony_ci } 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_ci return 0; 35678c2ecf20Sopenharmony_ci} 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci/* 35718c2ecf20Sopenharmony_ci * MEGARAID 'FW' commands. 35728c2ecf20Sopenharmony_ci */ 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci/** 35758c2ecf20Sopenharmony_ci * mega_is_bios_enabled() 35768c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 35778c2ecf20Sopenharmony_ci * 35788c2ecf20Sopenharmony_ci * issue command to find out if the BIOS is enabled for this controller 35798c2ecf20Sopenharmony_ci */ 35808c2ecf20Sopenharmony_cistatic int 35818c2ecf20Sopenharmony_cimega_is_bios_enabled(adapter_t *adapter) 35828c2ecf20Sopenharmony_ci{ 35838c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 35848c2ecf20Sopenharmony_ci mbox_t *mbox; 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci raw_mbox[0] = IS_BIOS_ENABLED; 35958c2ecf20Sopenharmony_ci raw_mbox[2] = GET_BIOS; 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci issue_scb_block(adapter, raw_mbox); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci return *(char *)adapter->mega_buffer; 36008c2ecf20Sopenharmony_ci} 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci/** 36048c2ecf20Sopenharmony_ci * mega_enum_raid_scsi() 36058c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 36068c2ecf20Sopenharmony_ci * 36078c2ecf20Sopenharmony_ci * Find out what channels are RAID/SCSI. This information is used to 36088c2ecf20Sopenharmony_ci * differentiate the virtual channels and physical channels and to support 36098c2ecf20Sopenharmony_ci * ROMB feature and non-disk devices. 36108c2ecf20Sopenharmony_ci */ 36118c2ecf20Sopenharmony_cistatic void 36128c2ecf20Sopenharmony_cimega_enum_raid_scsi(adapter_t *adapter) 36138c2ecf20Sopenharmony_ci{ 36148c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 36158c2ecf20Sopenharmony_ci mbox_t *mbox; 36168c2ecf20Sopenharmony_ci int i; 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci /* 36238c2ecf20Sopenharmony_ci * issue command to find out what channels are raid/scsi 36248c2ecf20Sopenharmony_ci */ 36258c2ecf20Sopenharmony_ci raw_mbox[0] = CHNL_CLASS; 36268c2ecf20Sopenharmony_ci raw_mbox[2] = GET_CHNL_CLASS; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci /* 36338c2ecf20Sopenharmony_ci * Non-ROMB firmware fail this command, so all channels 36348c2ecf20Sopenharmony_ci * must be shown RAID 36358c2ecf20Sopenharmony_ci */ 36368c2ecf20Sopenharmony_ci adapter->mega_ch_class = 0xFF; 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci if(!issue_scb_block(adapter, raw_mbox)) { 36398c2ecf20Sopenharmony_ci adapter->mega_ch_class = *((char *)adapter->mega_buffer); 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci for( i = 0; i < adapter->product_info.nchannels; i++ ) { 36448c2ecf20Sopenharmony_ci if( (adapter->mega_ch_class >> i) & 0x01 ) { 36458c2ecf20Sopenharmony_ci dev_info(&adapter->dev->dev, "channel[%d] is raid\n", 36468c2ecf20Sopenharmony_ci i); 36478c2ecf20Sopenharmony_ci } 36488c2ecf20Sopenharmony_ci else { 36498c2ecf20Sopenharmony_ci dev_info(&adapter->dev->dev, "channel[%d] is scsi\n", 36508c2ecf20Sopenharmony_ci i); 36518c2ecf20Sopenharmony_ci } 36528c2ecf20Sopenharmony_ci } 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci return; 36558c2ecf20Sopenharmony_ci} 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci/** 36598c2ecf20Sopenharmony_ci * mega_get_boot_drv() 36608c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 36618c2ecf20Sopenharmony_ci * 36628c2ecf20Sopenharmony_ci * Find out which device is the boot device. Note, any logical drive or any 36638c2ecf20Sopenharmony_ci * phyical device (e.g., a CDROM) can be designated as a boot device. 36648c2ecf20Sopenharmony_ci */ 36658c2ecf20Sopenharmony_cistatic void 36668c2ecf20Sopenharmony_cimega_get_boot_drv(adapter_t *adapter) 36678c2ecf20Sopenharmony_ci{ 36688c2ecf20Sopenharmony_ci struct private_bios_data *prv_bios_data; 36698c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 36708c2ecf20Sopenharmony_ci mbox_t *mbox; 36718c2ecf20Sopenharmony_ci u16 cksum = 0; 36728c2ecf20Sopenharmony_ci u8 *cksum_p; 36738c2ecf20Sopenharmony_ci u8 boot_pdrv; 36748c2ecf20Sopenharmony_ci int i; 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci raw_mbox[0] = BIOS_PVT_DATA; 36818c2ecf20Sopenharmony_ci raw_mbox[2] = GET_BIOS_PVT_DATA; 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci adapter->boot_ldrv_enabled = 0; 36888c2ecf20Sopenharmony_ci adapter->boot_ldrv = 0; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci adapter->boot_pdrv_enabled = 0; 36918c2ecf20Sopenharmony_ci adapter->boot_pdrv_ch = 0; 36928c2ecf20Sopenharmony_ci adapter->boot_pdrv_tgt = 0; 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci if(issue_scb_block(adapter, raw_mbox) == 0) { 36958c2ecf20Sopenharmony_ci prv_bios_data = 36968c2ecf20Sopenharmony_ci (struct private_bios_data *)adapter->mega_buffer; 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci cksum = 0; 36998c2ecf20Sopenharmony_ci cksum_p = (char *)prv_bios_data; 37008c2ecf20Sopenharmony_ci for (i = 0; i < 14; i++ ) { 37018c2ecf20Sopenharmony_ci cksum += (u16)(*cksum_p++); 37028c2ecf20Sopenharmony_ci } 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_ci if (prv_bios_data->cksum == (u16)(0-cksum) ) { 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci /* 37078c2ecf20Sopenharmony_ci * If MSB is set, a physical drive is set as boot 37088c2ecf20Sopenharmony_ci * device 37098c2ecf20Sopenharmony_ci */ 37108c2ecf20Sopenharmony_ci if( prv_bios_data->boot_drv & 0x80 ) { 37118c2ecf20Sopenharmony_ci adapter->boot_pdrv_enabled = 1; 37128c2ecf20Sopenharmony_ci boot_pdrv = prv_bios_data->boot_drv & 0x7F; 37138c2ecf20Sopenharmony_ci adapter->boot_pdrv_ch = boot_pdrv / 16; 37148c2ecf20Sopenharmony_ci adapter->boot_pdrv_tgt = boot_pdrv % 16; 37158c2ecf20Sopenharmony_ci } 37168c2ecf20Sopenharmony_ci else { 37178c2ecf20Sopenharmony_ci adapter->boot_ldrv_enabled = 1; 37188c2ecf20Sopenharmony_ci adapter->boot_ldrv = prv_bios_data->boot_drv; 37198c2ecf20Sopenharmony_ci } 37208c2ecf20Sopenharmony_ci } 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci} 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci/** 37268c2ecf20Sopenharmony_ci * mega_support_random_del() 37278c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 37288c2ecf20Sopenharmony_ci * 37298c2ecf20Sopenharmony_ci * Find out if this controller supports random deletion and addition of 37308c2ecf20Sopenharmony_ci * logical drives 37318c2ecf20Sopenharmony_ci */ 37328c2ecf20Sopenharmony_cistatic int 37338c2ecf20Sopenharmony_cimega_support_random_del(adapter_t *adapter) 37348c2ecf20Sopenharmony_ci{ 37358c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 37368c2ecf20Sopenharmony_ci mbox_t *mbox; 37378c2ecf20Sopenharmony_ci int rval; 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci /* 37448c2ecf20Sopenharmony_ci * issue command 37458c2ecf20Sopenharmony_ci */ 37468c2ecf20Sopenharmony_ci raw_mbox[0] = FC_DEL_LOGDRV; 37478c2ecf20Sopenharmony_ci raw_mbox[2] = OP_SUP_DEL_LOGDRV; 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci rval = issue_scb_block(adapter, raw_mbox); 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci return !rval; 37528c2ecf20Sopenharmony_ci} 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_ci/** 37568c2ecf20Sopenharmony_ci * mega_support_ext_cdb() 37578c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 37588c2ecf20Sopenharmony_ci * 37598c2ecf20Sopenharmony_ci * Find out if this firmware support cdblen > 10 37608c2ecf20Sopenharmony_ci */ 37618c2ecf20Sopenharmony_cistatic int 37628c2ecf20Sopenharmony_cimega_support_ext_cdb(adapter_t *adapter) 37638c2ecf20Sopenharmony_ci{ 37648c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 37658c2ecf20Sopenharmony_ci mbox_t *mbox; 37668c2ecf20Sopenharmony_ci int rval; 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 37718c2ecf20Sopenharmony_ci /* 37728c2ecf20Sopenharmony_ci * issue command to find out if controller supports extended CDBs. 37738c2ecf20Sopenharmony_ci */ 37748c2ecf20Sopenharmony_ci raw_mbox[0] = 0xA4; 37758c2ecf20Sopenharmony_ci raw_mbox[2] = 0x16; 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci rval = issue_scb_block(adapter, raw_mbox); 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci return !rval; 37808c2ecf20Sopenharmony_ci} 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci 37838c2ecf20Sopenharmony_ci/** 37848c2ecf20Sopenharmony_ci * mega_del_logdrv() 37858c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 37868c2ecf20Sopenharmony_ci * @logdrv: logical drive to be deleted 37878c2ecf20Sopenharmony_ci * 37888c2ecf20Sopenharmony_ci * Delete the specified logical drive. It is the responsibility of the user 37898c2ecf20Sopenharmony_ci * app to let the OS know about this operation. 37908c2ecf20Sopenharmony_ci */ 37918c2ecf20Sopenharmony_cistatic int 37928c2ecf20Sopenharmony_cimega_del_logdrv(adapter_t *adapter, int logdrv) 37938c2ecf20Sopenharmony_ci{ 37948c2ecf20Sopenharmony_ci unsigned long flags; 37958c2ecf20Sopenharmony_ci scb_t *scb; 37968c2ecf20Sopenharmony_ci int rval; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci /* 37998c2ecf20Sopenharmony_ci * Stop sending commands to the controller, queue them internally. 38008c2ecf20Sopenharmony_ci * When deletion is complete, ISR will flush the queue. 38018c2ecf20Sopenharmony_ci */ 38028c2ecf20Sopenharmony_ci atomic_set(&adapter->quiescent, 1); 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci /* 38058c2ecf20Sopenharmony_ci * Wait till all the issued commands are complete and there are no 38068c2ecf20Sopenharmony_ci * commands in the pending queue 38078c2ecf20Sopenharmony_ci */ 38088c2ecf20Sopenharmony_ci while (atomic_read(&adapter->pend_cmds) > 0 || 38098c2ecf20Sopenharmony_ci !list_empty(&adapter->pending_list)) 38108c2ecf20Sopenharmony_ci msleep(1000); /* sleep for 1s */ 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci rval = mega_do_del_logdrv(adapter, logdrv); 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci /* 38178c2ecf20Sopenharmony_ci * If delete operation was successful, add 0x80 to the logical drive 38188c2ecf20Sopenharmony_ci * ids for commands in the pending queue. 38198c2ecf20Sopenharmony_ci */ 38208c2ecf20Sopenharmony_ci if (adapter->read_ldidmap) { 38218c2ecf20Sopenharmony_ci struct list_head *pos; 38228c2ecf20Sopenharmony_ci list_for_each(pos, &adapter->pending_list) { 38238c2ecf20Sopenharmony_ci scb = list_entry(pos, scb_t, list); 38248c2ecf20Sopenharmony_ci if (scb->pthru->logdrv < 0x80 ) 38258c2ecf20Sopenharmony_ci scb->pthru->logdrv += 0x80; 38268c2ecf20Sopenharmony_ci } 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci atomic_set(&adapter->quiescent, 0); 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci mega_runpendq(adapter); 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci return rval; 38368c2ecf20Sopenharmony_ci} 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_cistatic int 38408c2ecf20Sopenharmony_cimega_do_del_logdrv(adapter_t *adapter, int logdrv) 38418c2ecf20Sopenharmony_ci{ 38428c2ecf20Sopenharmony_ci megacmd_t mc; 38438c2ecf20Sopenharmony_ci int rval; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci memset( &mc, 0, sizeof(megacmd_t)); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci mc.cmd = FC_DEL_LOGDRV; 38488c2ecf20Sopenharmony_ci mc.opcode = OP_DEL_LOGDRV; 38498c2ecf20Sopenharmony_ci mc.subopcode = logdrv; 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci rval = mega_internal_command(adapter, &mc, NULL); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci /* log this event */ 38548c2ecf20Sopenharmony_ci if(rval) { 38558c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "Delete LD-%d failed", logdrv); 38568c2ecf20Sopenharmony_ci return rval; 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci /* 38608c2ecf20Sopenharmony_ci * After deleting first logical drive, the logical drives must be 38618c2ecf20Sopenharmony_ci * addressed by adding 0x80 to the logical drive id. 38628c2ecf20Sopenharmony_ci */ 38638c2ecf20Sopenharmony_ci adapter->read_ldidmap = 1; 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci return rval; 38668c2ecf20Sopenharmony_ci} 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci/** 38708c2ecf20Sopenharmony_ci * mega_get_max_sgl() 38718c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 38728c2ecf20Sopenharmony_ci * 38738c2ecf20Sopenharmony_ci * Find out the maximum number of scatter-gather elements supported by this 38748c2ecf20Sopenharmony_ci * version of the firmware 38758c2ecf20Sopenharmony_ci */ 38768c2ecf20Sopenharmony_cistatic void 38778c2ecf20Sopenharmony_cimega_get_max_sgl(adapter_t *adapter) 38788c2ecf20Sopenharmony_ci{ 38798c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 38808c2ecf20Sopenharmony_ci mbox_t *mbox; 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci memset(mbox, 0, sizeof(raw_mbox)); 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci raw_mbox[0] = MAIN_MISC_OPCODE; 38918c2ecf20Sopenharmony_ci raw_mbox[2] = GET_MAX_SG_SUPPORT; 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci if( issue_scb_block(adapter, raw_mbox) ) { 38958c2ecf20Sopenharmony_ci /* 38968c2ecf20Sopenharmony_ci * f/w does not support this command. Choose the default value 38978c2ecf20Sopenharmony_ci */ 38988c2ecf20Sopenharmony_ci adapter->sglen = MIN_SGLIST; 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci else { 39018c2ecf20Sopenharmony_ci adapter->sglen = *((char *)adapter->mega_buffer); 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci /* 39048c2ecf20Sopenharmony_ci * Make sure this is not more than the resources we are 39058c2ecf20Sopenharmony_ci * planning to allocate 39068c2ecf20Sopenharmony_ci */ 39078c2ecf20Sopenharmony_ci if ( adapter->sglen > MAX_SGLIST ) 39088c2ecf20Sopenharmony_ci adapter->sglen = MAX_SGLIST; 39098c2ecf20Sopenharmony_ci } 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci return; 39128c2ecf20Sopenharmony_ci} 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci/** 39168c2ecf20Sopenharmony_ci * mega_support_cluster() 39178c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 39188c2ecf20Sopenharmony_ci * 39198c2ecf20Sopenharmony_ci * Find out if this firmware support cluster calls. 39208c2ecf20Sopenharmony_ci */ 39218c2ecf20Sopenharmony_cistatic int 39228c2ecf20Sopenharmony_cimega_support_cluster(adapter_t *adapter) 39238c2ecf20Sopenharmony_ci{ 39248c2ecf20Sopenharmony_ci unsigned char raw_mbox[sizeof(struct mbox_out)]; 39258c2ecf20Sopenharmony_ci mbox_t *mbox; 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci mbox = (mbox_t *)raw_mbox; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci memset(mbox, 0, sizeof(raw_mbox)); 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci /* 39368c2ecf20Sopenharmony_ci * Try to get the initiator id. This command will succeed iff the 39378c2ecf20Sopenharmony_ci * clustering is available on this HBA. 39388c2ecf20Sopenharmony_ci */ 39398c2ecf20Sopenharmony_ci raw_mbox[0] = MEGA_GET_TARGET_ID; 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci if( issue_scb_block(adapter, raw_mbox) == 0 ) { 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci /* 39448c2ecf20Sopenharmony_ci * Cluster support available. Get the initiator target id. 39458c2ecf20Sopenharmony_ci * Tell our id to mid-layer too. 39468c2ecf20Sopenharmony_ci */ 39478c2ecf20Sopenharmony_ci adapter->this_id = *(u32 *)adapter->mega_buffer; 39488c2ecf20Sopenharmony_ci adapter->host->this_id = adapter->this_id; 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci return 1; 39518c2ecf20Sopenharmony_ci } 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci return 0; 39548c2ecf20Sopenharmony_ci} 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 39578c2ecf20Sopenharmony_ci/** 39588c2ecf20Sopenharmony_ci * mega_adapinq() 39598c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 39608c2ecf20Sopenharmony_ci * @dma_handle: DMA address of the buffer 39618c2ecf20Sopenharmony_ci * 39628c2ecf20Sopenharmony_ci * Issue internal commands while interrupts are available. 39638c2ecf20Sopenharmony_ci * We only issue direct mailbox commands from within the driver. ioctl() 39648c2ecf20Sopenharmony_ci * interface using these routines can issue passthru commands. 39658c2ecf20Sopenharmony_ci */ 39668c2ecf20Sopenharmony_cistatic int 39678c2ecf20Sopenharmony_cimega_adapinq(adapter_t *adapter, dma_addr_t dma_handle) 39688c2ecf20Sopenharmony_ci{ 39698c2ecf20Sopenharmony_ci megacmd_t mc; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci memset(&mc, 0, sizeof(megacmd_t)); 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci if( adapter->flag & BOARD_40LD ) { 39748c2ecf20Sopenharmony_ci mc.cmd = FC_NEW_CONFIG; 39758c2ecf20Sopenharmony_ci mc.opcode = NC_SUBOP_ENQUIRY3; 39768c2ecf20Sopenharmony_ci mc.subopcode = ENQ3_GET_SOLICITED_FULL; 39778c2ecf20Sopenharmony_ci } 39788c2ecf20Sopenharmony_ci else { 39798c2ecf20Sopenharmony_ci mc.cmd = MEGA_MBOXCMD_ADPEXTINQ; 39808c2ecf20Sopenharmony_ci } 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci mc.xferaddr = (u32)dma_handle; 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci if ( mega_internal_command(adapter, &mc, NULL) != 0 ) { 39858c2ecf20Sopenharmony_ci return -1; 39868c2ecf20Sopenharmony_ci } 39878c2ecf20Sopenharmony_ci 39888c2ecf20Sopenharmony_ci return 0; 39898c2ecf20Sopenharmony_ci} 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci/** 39938c2ecf20Sopenharmony_ci * mega_internal_dev_inquiry() 39948c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 39958c2ecf20Sopenharmony_ci * @ch: channel for this device 39968c2ecf20Sopenharmony_ci * @tgt: ID of this device 39978c2ecf20Sopenharmony_ci * @buf_dma_handle: DMA address of the buffer 39988c2ecf20Sopenharmony_ci * 39998c2ecf20Sopenharmony_ci * Issue the scsi inquiry for the specified device. 40008c2ecf20Sopenharmony_ci */ 40018c2ecf20Sopenharmony_cistatic int 40028c2ecf20Sopenharmony_cimega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, 40038c2ecf20Sopenharmony_ci dma_addr_t buf_dma_handle) 40048c2ecf20Sopenharmony_ci{ 40058c2ecf20Sopenharmony_ci mega_passthru *pthru; 40068c2ecf20Sopenharmony_ci dma_addr_t pthru_dma_handle; 40078c2ecf20Sopenharmony_ci megacmd_t mc; 40088c2ecf20Sopenharmony_ci int rval; 40098c2ecf20Sopenharmony_ci struct pci_dev *pdev; 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci /* 40138c2ecf20Sopenharmony_ci * For all internal commands, the buffer must be allocated in <4GB 40148c2ecf20Sopenharmony_ci * address range 40158c2ecf20Sopenharmony_ci */ 40168c2ecf20Sopenharmony_ci if( make_local_pdev(adapter, &pdev) != 0 ) return -1; 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci pthru = dma_alloc_coherent(&pdev->dev, sizeof(mega_passthru), 40198c2ecf20Sopenharmony_ci &pthru_dma_handle, GFP_KERNEL); 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci if( pthru == NULL ) { 40228c2ecf20Sopenharmony_ci free_local_pdev(pdev); 40238c2ecf20Sopenharmony_ci return -1; 40248c2ecf20Sopenharmony_ci } 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci pthru->timeout = 2; 40278c2ecf20Sopenharmony_ci pthru->ars = 1; 40288c2ecf20Sopenharmony_ci pthru->reqsenselen = 14; 40298c2ecf20Sopenharmony_ci pthru->islogical = 0; 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : ch; 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci pthru->target = (adapter->flag & BOARD_40LD) ? (ch << 4)|tgt : tgt; 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci pthru->cdblen = 6; 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci pthru->cdb[0] = INQUIRY; 40388c2ecf20Sopenharmony_ci pthru->cdb[1] = 0; 40398c2ecf20Sopenharmony_ci pthru->cdb[2] = 0; 40408c2ecf20Sopenharmony_ci pthru->cdb[3] = 0; 40418c2ecf20Sopenharmony_ci pthru->cdb[4] = 255; 40428c2ecf20Sopenharmony_ci pthru->cdb[5] = 0; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci pthru->dataxferaddr = (u32)buf_dma_handle; 40468c2ecf20Sopenharmony_ci pthru->dataxferlen = 256; 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci memset(&mc, 0, sizeof(megacmd_t)); 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci mc.cmd = MEGA_MBOXCMD_PASSTHRU; 40518c2ecf20Sopenharmony_ci mc.xferaddr = (u32)pthru_dma_handle; 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci rval = mega_internal_command(adapter, &mc, pthru); 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(mega_passthru), pthru, 40568c2ecf20Sopenharmony_ci pthru_dma_handle); 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci free_local_pdev(pdev); 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ci return rval; 40618c2ecf20Sopenharmony_ci} 40628c2ecf20Sopenharmony_ci#endif 40638c2ecf20Sopenharmony_ci 40648c2ecf20Sopenharmony_ci/** 40658c2ecf20Sopenharmony_ci * mega_internal_command() 40668c2ecf20Sopenharmony_ci * @adapter: pointer to our soft state 40678c2ecf20Sopenharmony_ci * @mc: the mailbox command 40688c2ecf20Sopenharmony_ci * @pthru: Passthru structure for DCDB commands 40698c2ecf20Sopenharmony_ci * 40708c2ecf20Sopenharmony_ci * Issue the internal commands in interrupt mode. 40718c2ecf20Sopenharmony_ci * The last argument is the address of the passthru structure if the command 40728c2ecf20Sopenharmony_ci * to be fired is a passthru command 40738c2ecf20Sopenharmony_ci * 40748c2ecf20Sopenharmony_ci * Note: parameter 'pthru' is null for non-passthru commands. 40758c2ecf20Sopenharmony_ci */ 40768c2ecf20Sopenharmony_cistatic int 40778c2ecf20Sopenharmony_cimega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) 40788c2ecf20Sopenharmony_ci{ 40798c2ecf20Sopenharmony_ci unsigned long flags; 40808c2ecf20Sopenharmony_ci scb_t *scb; 40818c2ecf20Sopenharmony_ci int rval; 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci /* 40848c2ecf20Sopenharmony_ci * The internal commands share one command id and hence are 40858c2ecf20Sopenharmony_ci * serialized. This is so because we want to reserve maximum number of 40868c2ecf20Sopenharmony_ci * available command ids for the I/O commands. 40878c2ecf20Sopenharmony_ci */ 40888c2ecf20Sopenharmony_ci mutex_lock(&adapter->int_mtx); 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci scb = &adapter->int_scb; 40918c2ecf20Sopenharmony_ci memset(scb, 0, sizeof(scb_t)); 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci scb->idx = CMDID_INT_CMDS; 40948c2ecf20Sopenharmony_ci scb->state |= SCB_ACTIVE | SCB_PENDQ; 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci memcpy(scb->raw_mbox, mc, sizeof(megacmd_t)); 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci /* 40998c2ecf20Sopenharmony_ci * Is it a passthru command 41008c2ecf20Sopenharmony_ci */ 41018c2ecf20Sopenharmony_ci if (mc->cmd == MEGA_MBOXCMD_PASSTHRU) 41028c2ecf20Sopenharmony_ci scb->pthru = pthru; 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->lock, flags); 41058c2ecf20Sopenharmony_ci list_add_tail(&scb->list, &adapter->pending_list); 41068c2ecf20Sopenharmony_ci /* 41078c2ecf20Sopenharmony_ci * Check if the HBA is in quiescent state, e.g., during a 41088c2ecf20Sopenharmony_ci * delete logical drive opertion. If it is, don't run 41098c2ecf20Sopenharmony_ci * the pending_list. 41108c2ecf20Sopenharmony_ci */ 41118c2ecf20Sopenharmony_ci if (atomic_read(&adapter->quiescent) == 0) 41128c2ecf20Sopenharmony_ci mega_runpendq(adapter); 41138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->lock, flags); 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci wait_for_completion(&adapter->int_waitq); 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci mc->status = rval = adapter->int_status; 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci /* 41208c2ecf20Sopenharmony_ci * Print a debug message for all failed commands. Applications can use 41218c2ecf20Sopenharmony_ci * this information. 41228c2ecf20Sopenharmony_ci */ 41238c2ecf20Sopenharmony_ci if (rval && trace_level) { 41248c2ecf20Sopenharmony_ci dev_info(&adapter->dev->dev, "cmd [%x, %x, %x] status:[%x]\n", 41258c2ecf20Sopenharmony_ci mc->cmd, mc->opcode, mc->subopcode, rval); 41268c2ecf20Sopenharmony_ci } 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci mutex_unlock(&adapter->int_mtx); 41298c2ecf20Sopenharmony_ci return rval; 41308c2ecf20Sopenharmony_ci} 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_cistatic struct scsi_host_template megaraid_template = { 41338c2ecf20Sopenharmony_ci .module = THIS_MODULE, 41348c2ecf20Sopenharmony_ci .name = "MegaRAID", 41358c2ecf20Sopenharmony_ci .proc_name = "megaraid_legacy", 41368c2ecf20Sopenharmony_ci .info = megaraid_info, 41378c2ecf20Sopenharmony_ci .queuecommand = megaraid_queue, 41388c2ecf20Sopenharmony_ci .bios_param = megaraid_biosparam, 41398c2ecf20Sopenharmony_ci .max_sectors = MAX_SECTORS_PER_IO, 41408c2ecf20Sopenharmony_ci .can_queue = MAX_COMMANDS, 41418c2ecf20Sopenharmony_ci .this_id = DEFAULT_INITIATOR_ID, 41428c2ecf20Sopenharmony_ci .sg_tablesize = MAX_SGLIST, 41438c2ecf20Sopenharmony_ci .cmd_per_lun = DEF_CMD_PER_LUN, 41448c2ecf20Sopenharmony_ci .eh_abort_handler = megaraid_abort, 41458c2ecf20Sopenharmony_ci .eh_device_reset_handler = megaraid_reset, 41468c2ecf20Sopenharmony_ci .eh_bus_reset_handler = megaraid_reset, 41478c2ecf20Sopenharmony_ci .eh_host_reset_handler = megaraid_reset, 41488c2ecf20Sopenharmony_ci .no_write_same = 1, 41498c2ecf20Sopenharmony_ci}; 41508c2ecf20Sopenharmony_ci 41518c2ecf20Sopenharmony_cistatic int 41528c2ecf20Sopenharmony_cimegaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 41538c2ecf20Sopenharmony_ci{ 41548c2ecf20Sopenharmony_ci struct Scsi_Host *host; 41558c2ecf20Sopenharmony_ci adapter_t *adapter; 41568c2ecf20Sopenharmony_ci unsigned long mega_baseport, tbase, flag = 0; 41578c2ecf20Sopenharmony_ci u16 subsysid, subsysvid; 41588c2ecf20Sopenharmony_ci u8 pci_bus, pci_dev_func; 41598c2ecf20Sopenharmony_ci int irq, i, j; 41608c2ecf20Sopenharmony_ci int error = -ENODEV; 41618c2ecf20Sopenharmony_ci 41628c2ecf20Sopenharmony_ci if (hba_count >= MAX_CONTROLLERS) 41638c2ecf20Sopenharmony_ci goto out; 41648c2ecf20Sopenharmony_ci 41658c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) 41668c2ecf20Sopenharmony_ci goto out; 41678c2ecf20Sopenharmony_ci pci_set_master(pdev); 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_ci pci_bus = pdev->bus->number; 41708c2ecf20Sopenharmony_ci pci_dev_func = pdev->devfn; 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci /* 41738c2ecf20Sopenharmony_ci * The megaraid3 stuff reports the ID of the Intel part which is not 41748c2ecf20Sopenharmony_ci * remotely specific to the megaraid 41758c2ecf20Sopenharmony_ci */ 41768c2ecf20Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 41778c2ecf20Sopenharmony_ci u16 magic; 41788c2ecf20Sopenharmony_ci /* 41798c2ecf20Sopenharmony_ci * Don't fall over the Compaq management cards using the same 41808c2ecf20Sopenharmony_ci * PCI identifier 41818c2ecf20Sopenharmony_ci */ 41828c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ && 41838c2ecf20Sopenharmony_ci pdev->subsystem_device == 0xC000) 41848c2ecf20Sopenharmony_ci goto out_disable_device; 41858c2ecf20Sopenharmony_ci /* Now check the magic signature byte */ 41868c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); 41878c2ecf20Sopenharmony_ci if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE) 41888c2ecf20Sopenharmony_ci goto out_disable_device; 41898c2ecf20Sopenharmony_ci /* Ok it is probably a megaraid */ 41908c2ecf20Sopenharmony_ci } 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci /* 41938c2ecf20Sopenharmony_ci * For these vendor and device ids, signature offsets are not 41948c2ecf20Sopenharmony_ci * valid and 64 bit is implicit 41958c2ecf20Sopenharmony_ci */ 41968c2ecf20Sopenharmony_ci if (id->driver_data & BOARD_64BIT) 41978c2ecf20Sopenharmony_ci flag |= BOARD_64BIT; 41988c2ecf20Sopenharmony_ci else { 41998c2ecf20Sopenharmony_ci u32 magic64; 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCI_CONF_AMISIG64, &magic64); 42028c2ecf20Sopenharmony_ci if (magic64 == HBA_SIGNATURE_64BIT) 42038c2ecf20Sopenharmony_ci flag |= BOARD_64BIT; 42048c2ecf20Sopenharmony_ci } 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_ci subsysvid = pdev->subsystem_vendor; 42078c2ecf20Sopenharmony_ci subsysid = pdev->subsystem_device; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci dev_notice(&pdev->dev, "found 0x%4.04x:0x%4.04x\n", 42108c2ecf20Sopenharmony_ci id->vendor, id->device); 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci /* Read the base port and IRQ from PCI */ 42138c2ecf20Sopenharmony_ci mega_baseport = pci_resource_start(pdev, 0); 42148c2ecf20Sopenharmony_ci irq = pdev->irq; 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci tbase = mega_baseport; 42178c2ecf20Sopenharmony_ci if (pci_resource_flags(pdev, 0) & IORESOURCE_MEM) { 42188c2ecf20Sopenharmony_ci flag |= BOARD_MEMMAP; 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci if (!request_mem_region(mega_baseport, 128, "megaraid")) { 42218c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "mem region busy!\n"); 42228c2ecf20Sopenharmony_ci goto out_disable_device; 42238c2ecf20Sopenharmony_ci } 42248c2ecf20Sopenharmony_ci 42258c2ecf20Sopenharmony_ci mega_baseport = (unsigned long)ioremap(mega_baseport, 128); 42268c2ecf20Sopenharmony_ci if (!mega_baseport) { 42278c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "could not map hba memory\n"); 42288c2ecf20Sopenharmony_ci goto out_release_region; 42298c2ecf20Sopenharmony_ci } 42308c2ecf20Sopenharmony_ci } else { 42318c2ecf20Sopenharmony_ci flag |= BOARD_IOMAP; 42328c2ecf20Sopenharmony_ci mega_baseport += 0x10; 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci if (!request_region(mega_baseport, 16, "megaraid")) 42358c2ecf20Sopenharmony_ci goto out_disable_device; 42368c2ecf20Sopenharmony_ci } 42378c2ecf20Sopenharmony_ci 42388c2ecf20Sopenharmony_ci /* Initialize SCSI Host structure */ 42398c2ecf20Sopenharmony_ci host = scsi_host_alloc(&megaraid_template, sizeof(adapter_t)); 42408c2ecf20Sopenharmony_ci if (!host) 42418c2ecf20Sopenharmony_ci goto out_iounmap; 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci adapter = (adapter_t *)host->hostdata; 42448c2ecf20Sopenharmony_ci memset(adapter, 0, sizeof(adapter_t)); 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci dev_notice(&pdev->dev, 42478c2ecf20Sopenharmony_ci "scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n", 42488c2ecf20Sopenharmony_ci host->host_no, mega_baseport, irq); 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci adapter->base = mega_baseport; 42518c2ecf20Sopenharmony_ci if (flag & BOARD_MEMMAP) 42528c2ecf20Sopenharmony_ci adapter->mmio_base = (void __iomem *) mega_baseport; 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->free_list); 42558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->pending_list); 42568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->completed_list); 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci adapter->flag = flag; 42598c2ecf20Sopenharmony_ci spin_lock_init(&adapter->lock); 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci host->cmd_per_lun = max_cmd_per_lun; 42628c2ecf20Sopenharmony_ci host->max_sectors = max_sectors_per_io; 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci adapter->dev = pdev; 42658c2ecf20Sopenharmony_ci adapter->host = host; 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci adapter->host->irq = irq; 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci if (flag & BOARD_MEMMAP) 42708c2ecf20Sopenharmony_ci adapter->host->base = tbase; 42718c2ecf20Sopenharmony_ci else { 42728c2ecf20Sopenharmony_ci adapter->host->io_port = tbase; 42738c2ecf20Sopenharmony_ci adapter->host->n_io_port = 16; 42748c2ecf20Sopenharmony_ci } 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_ci adapter->host->unique_id = (pci_bus << 8) | pci_dev_func; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci /* 42798c2ecf20Sopenharmony_ci * Allocate buffer to issue internal commands. 42808c2ecf20Sopenharmony_ci */ 42818c2ecf20Sopenharmony_ci adapter->mega_buffer = dma_alloc_coherent(&adapter->dev->dev, 42828c2ecf20Sopenharmony_ci MEGA_BUFFER_SIZE, 42838c2ecf20Sopenharmony_ci &adapter->buf_dma_handle, 42848c2ecf20Sopenharmony_ci GFP_KERNEL); 42858c2ecf20Sopenharmony_ci if (!adapter->mega_buffer) { 42868c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "out of RAM\n"); 42878c2ecf20Sopenharmony_ci goto out_host_put; 42888c2ecf20Sopenharmony_ci } 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci adapter->scb_list = kmalloc_array(MAX_COMMANDS, sizeof(scb_t), 42918c2ecf20Sopenharmony_ci GFP_KERNEL); 42928c2ecf20Sopenharmony_ci if (!adapter->scb_list) { 42938c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "out of RAM\n"); 42948c2ecf20Sopenharmony_ci goto out_free_cmd_buffer; 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ? 42988c2ecf20Sopenharmony_ci megaraid_isr_memmapped : megaraid_isr_iomapped, 42998c2ecf20Sopenharmony_ci IRQF_SHARED, "megaraid", adapter)) { 43008c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Couldn't register IRQ %d!\n", irq); 43018c2ecf20Sopenharmony_ci goto out_free_scb_list; 43028c2ecf20Sopenharmony_ci } 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci if (mega_setup_mailbox(adapter)) 43058c2ecf20Sopenharmony_ci goto out_free_irq; 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ci if (mega_query_adapter(adapter)) 43088c2ecf20Sopenharmony_ci goto out_free_mbox; 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci /* 43118c2ecf20Sopenharmony_ci * Have checks for some buggy f/w 43128c2ecf20Sopenharmony_ci */ 43138c2ecf20Sopenharmony_ci if ((subsysid == 0x1111) && (subsysvid == 0x1111)) { 43148c2ecf20Sopenharmony_ci /* 43158c2ecf20Sopenharmony_ci * Which firmware 43168c2ecf20Sopenharmony_ci */ 43178c2ecf20Sopenharmony_ci if (!strcmp(adapter->fw_version, "3.00") || 43188c2ecf20Sopenharmony_ci !strcmp(adapter->fw_version, "3.01")) { 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 43218c2ecf20Sopenharmony_ci "Your card is a Dell PERC " 43228c2ecf20Sopenharmony_ci "2/SC RAID controller with " 43238c2ecf20Sopenharmony_ci "firmware\nmegaraid: 3.00 or 3.01. " 43248c2ecf20Sopenharmony_ci "This driver is known to have " 43258c2ecf20Sopenharmony_ci "corruption issues\nmegaraid: with " 43268c2ecf20Sopenharmony_ci "those firmware versions on this " 43278c2ecf20Sopenharmony_ci "specific card. In order\nmegaraid: " 43288c2ecf20Sopenharmony_ci "to protect your data, please upgrade " 43298c2ecf20Sopenharmony_ci "your firmware to version\nmegaraid: " 43308c2ecf20Sopenharmony_ci "3.10 or later, available from the " 43318c2ecf20Sopenharmony_ci "Dell Technical Support web\n" 43328c2ecf20Sopenharmony_ci "megaraid: site at\nhttp://support." 43338c2ecf20Sopenharmony_ci "dell.com/us/en/filelib/download/" 43348c2ecf20Sopenharmony_ci "index.asp?fileid=2940\n" 43358c2ecf20Sopenharmony_ci ); 43368c2ecf20Sopenharmony_ci } 43378c2ecf20Sopenharmony_ci } 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci /* 43408c2ecf20Sopenharmony_ci * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with 43418c2ecf20Sopenharmony_ci * firmware H.01.07, H.01.08, and H.01.09 disable 64 bit 43428c2ecf20Sopenharmony_ci * support, since this firmware cannot handle 64 bit 43438c2ecf20Sopenharmony_ci * addressing 43448c2ecf20Sopenharmony_ci */ 43458c2ecf20Sopenharmony_ci if ((subsysvid == PCI_VENDOR_ID_HP) && 43468c2ecf20Sopenharmony_ci ((subsysid == 0x60E7) || (subsysid == 0x60E8))) { 43478c2ecf20Sopenharmony_ci /* 43488c2ecf20Sopenharmony_ci * which firmware 43498c2ecf20Sopenharmony_ci */ 43508c2ecf20Sopenharmony_ci if (!strcmp(adapter->fw_version, "H01.07") || 43518c2ecf20Sopenharmony_ci !strcmp(adapter->fw_version, "H01.08") || 43528c2ecf20Sopenharmony_ci !strcmp(adapter->fw_version, "H01.09") ) { 43538c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 43548c2ecf20Sopenharmony_ci "Firmware H.01.07, " 43558c2ecf20Sopenharmony_ci "H.01.08, and H.01.09 on 1M/2M " 43568c2ecf20Sopenharmony_ci "controllers\n" 43578c2ecf20Sopenharmony_ci "do not support 64 bit " 43588c2ecf20Sopenharmony_ci "addressing.\nDISABLING " 43598c2ecf20Sopenharmony_ci "64 bit support.\n"); 43608c2ecf20Sopenharmony_ci adapter->flag &= ~BOARD_64BIT; 43618c2ecf20Sopenharmony_ci } 43628c2ecf20Sopenharmony_ci } 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci if (mega_is_bios_enabled(adapter)) 43658c2ecf20Sopenharmony_ci mega_hbas[hba_count].is_bios_enabled = 1; 43668c2ecf20Sopenharmony_ci mega_hbas[hba_count].hostdata_addr = adapter; 43678c2ecf20Sopenharmony_ci 43688c2ecf20Sopenharmony_ci /* 43698c2ecf20Sopenharmony_ci * Find out which channel is raid and which is scsi. This is 43708c2ecf20Sopenharmony_ci * for ROMB support. 43718c2ecf20Sopenharmony_ci */ 43728c2ecf20Sopenharmony_ci mega_enum_raid_scsi(adapter); 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci /* 43758c2ecf20Sopenharmony_ci * Find out if a logical drive is set as the boot drive. If 43768c2ecf20Sopenharmony_ci * there is one, will make that as the first logical drive. 43778c2ecf20Sopenharmony_ci * ROMB: Do we have to boot from a physical drive. Then all 43788c2ecf20Sopenharmony_ci * the physical drives would appear before the logical disks. 43798c2ecf20Sopenharmony_ci * Else, all the physical drives would be exported to the mid 43808c2ecf20Sopenharmony_ci * layer after logical drives. 43818c2ecf20Sopenharmony_ci */ 43828c2ecf20Sopenharmony_ci mega_get_boot_drv(adapter); 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci if (adapter->boot_pdrv_enabled) { 43858c2ecf20Sopenharmony_ci j = adapter->product_info.nchannels; 43868c2ecf20Sopenharmony_ci for( i = 0; i < j; i++ ) 43878c2ecf20Sopenharmony_ci adapter->logdrv_chan[i] = 0; 43888c2ecf20Sopenharmony_ci for( i = j; i < NVIRT_CHAN + j; i++ ) 43898c2ecf20Sopenharmony_ci adapter->logdrv_chan[i] = 1; 43908c2ecf20Sopenharmony_ci } else { 43918c2ecf20Sopenharmony_ci for (i = 0; i < NVIRT_CHAN; i++) 43928c2ecf20Sopenharmony_ci adapter->logdrv_chan[i] = 1; 43938c2ecf20Sopenharmony_ci for (i = NVIRT_CHAN; i < MAX_CHANNELS+NVIRT_CHAN; i++) 43948c2ecf20Sopenharmony_ci adapter->logdrv_chan[i] = 0; 43958c2ecf20Sopenharmony_ci adapter->mega_ch_class <<= NVIRT_CHAN; 43968c2ecf20Sopenharmony_ci } 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci /* 43998c2ecf20Sopenharmony_ci * Do we support random deletion and addition of logical 44008c2ecf20Sopenharmony_ci * drives 44018c2ecf20Sopenharmony_ci */ 44028c2ecf20Sopenharmony_ci adapter->read_ldidmap = 0; /* set it after first logdrv 44038c2ecf20Sopenharmony_ci delete cmd */ 44048c2ecf20Sopenharmony_ci adapter->support_random_del = mega_support_random_del(adapter); 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_ci /* Initialize SCBs */ 44078c2ecf20Sopenharmony_ci if (mega_init_scb(adapter)) 44088c2ecf20Sopenharmony_ci goto out_free_mbox; 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci /* 44118c2ecf20Sopenharmony_ci * Reset the pending commands counter 44128c2ecf20Sopenharmony_ci */ 44138c2ecf20Sopenharmony_ci atomic_set(&adapter->pend_cmds, 0); 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci /* 44168c2ecf20Sopenharmony_ci * Reset the adapter quiescent flag 44178c2ecf20Sopenharmony_ci */ 44188c2ecf20Sopenharmony_ci atomic_set(&adapter->quiescent, 0); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci hba_soft_state[hba_count] = adapter; 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci /* 44238c2ecf20Sopenharmony_ci * Fill in the structure which needs to be passed back to the 44248c2ecf20Sopenharmony_ci * application when it does an ioctl() for controller related 44258c2ecf20Sopenharmony_ci * information. 44268c2ecf20Sopenharmony_ci */ 44278c2ecf20Sopenharmony_ci i = hba_count; 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci mcontroller[i].base = mega_baseport; 44308c2ecf20Sopenharmony_ci mcontroller[i].irq = irq; 44318c2ecf20Sopenharmony_ci mcontroller[i].numldrv = adapter->numldrv; 44328c2ecf20Sopenharmony_ci mcontroller[i].pcibus = pci_bus; 44338c2ecf20Sopenharmony_ci mcontroller[i].pcidev = id->device; 44348c2ecf20Sopenharmony_ci mcontroller[i].pcifun = PCI_FUNC (pci_dev_func); 44358c2ecf20Sopenharmony_ci mcontroller[i].pciid = -1; 44368c2ecf20Sopenharmony_ci mcontroller[i].pcivendor = id->vendor; 44378c2ecf20Sopenharmony_ci mcontroller[i].pcislot = PCI_SLOT(pci_dev_func); 44388c2ecf20Sopenharmony_ci mcontroller[i].uid = (pci_bus << 8) | pci_dev_func; 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci 44418c2ecf20Sopenharmony_ci /* Set the Mode of addressing to 64 bit if we can */ 44428c2ecf20Sopenharmony_ci if ((adapter->flag & BOARD_64BIT) && (sizeof(dma_addr_t) == 8)) { 44438c2ecf20Sopenharmony_ci dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); 44448c2ecf20Sopenharmony_ci adapter->has_64bit_addr = 1; 44458c2ecf20Sopenharmony_ci } else { 44468c2ecf20Sopenharmony_ci dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 44478c2ecf20Sopenharmony_ci adapter->has_64bit_addr = 0; 44488c2ecf20Sopenharmony_ci } 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci mutex_init(&adapter->int_mtx); 44518c2ecf20Sopenharmony_ci init_completion(&adapter->int_waitq); 44528c2ecf20Sopenharmony_ci 44538c2ecf20Sopenharmony_ci adapter->this_id = DEFAULT_INITIATOR_ID; 44548c2ecf20Sopenharmony_ci adapter->host->this_id = DEFAULT_INITIATOR_ID; 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci#if MEGA_HAVE_CLUSTERING 44578c2ecf20Sopenharmony_ci /* 44588c2ecf20Sopenharmony_ci * Is cluster support enabled on this controller 44598c2ecf20Sopenharmony_ci * Note: In a cluster the HBAs ( the initiators ) will have 44608c2ecf20Sopenharmony_ci * different target IDs and we cannot assume it to be 7. Call 44618c2ecf20Sopenharmony_ci * to mega_support_cluster() will get the target ids also if 44628c2ecf20Sopenharmony_ci * the cluster support is available 44638c2ecf20Sopenharmony_ci */ 44648c2ecf20Sopenharmony_ci adapter->has_cluster = mega_support_cluster(adapter); 44658c2ecf20Sopenharmony_ci if (adapter->has_cluster) { 44668c2ecf20Sopenharmony_ci dev_notice(&pdev->dev, 44678c2ecf20Sopenharmony_ci "Cluster driver, initiator id:%d\n", 44688c2ecf20Sopenharmony_ci adapter->this_id); 44698c2ecf20Sopenharmony_ci } 44708c2ecf20Sopenharmony_ci#endif 44718c2ecf20Sopenharmony_ci 44728c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, host); 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci mega_create_proc_entry(hba_count, mega_proc_dir_entry); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci error = scsi_add_host(host, &pdev->dev); 44778c2ecf20Sopenharmony_ci if (error) 44788c2ecf20Sopenharmony_ci goto out_free_mbox; 44798c2ecf20Sopenharmony_ci 44808c2ecf20Sopenharmony_ci scsi_scan_host(host); 44818c2ecf20Sopenharmony_ci hba_count++; 44828c2ecf20Sopenharmony_ci return 0; 44838c2ecf20Sopenharmony_ci 44848c2ecf20Sopenharmony_ci out_free_mbox: 44858c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, sizeof(mbox64_t), 44868c2ecf20Sopenharmony_ci adapter->una_mbox64, adapter->una_mbox64_dma); 44878c2ecf20Sopenharmony_ci out_free_irq: 44888c2ecf20Sopenharmony_ci free_irq(adapter->host->irq, adapter); 44898c2ecf20Sopenharmony_ci out_free_scb_list: 44908c2ecf20Sopenharmony_ci kfree(adapter->scb_list); 44918c2ecf20Sopenharmony_ci out_free_cmd_buffer: 44928c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, MEGA_BUFFER_SIZE, 44938c2ecf20Sopenharmony_ci adapter->mega_buffer, adapter->buf_dma_handle); 44948c2ecf20Sopenharmony_ci out_host_put: 44958c2ecf20Sopenharmony_ci scsi_host_put(host); 44968c2ecf20Sopenharmony_ci out_iounmap: 44978c2ecf20Sopenharmony_ci if (flag & BOARD_MEMMAP) 44988c2ecf20Sopenharmony_ci iounmap((void *)mega_baseport); 44998c2ecf20Sopenharmony_ci out_release_region: 45008c2ecf20Sopenharmony_ci if (flag & BOARD_MEMMAP) 45018c2ecf20Sopenharmony_ci release_mem_region(tbase, 128); 45028c2ecf20Sopenharmony_ci else 45038c2ecf20Sopenharmony_ci release_region(mega_baseport, 16); 45048c2ecf20Sopenharmony_ci out_disable_device: 45058c2ecf20Sopenharmony_ci pci_disable_device(pdev); 45068c2ecf20Sopenharmony_ci out: 45078c2ecf20Sopenharmony_ci return error; 45088c2ecf20Sopenharmony_ci} 45098c2ecf20Sopenharmony_ci 45108c2ecf20Sopenharmony_cistatic void 45118c2ecf20Sopenharmony_ci__megaraid_shutdown(adapter_t *adapter) 45128c2ecf20Sopenharmony_ci{ 45138c2ecf20Sopenharmony_ci u_char raw_mbox[sizeof(struct mbox_out)]; 45148c2ecf20Sopenharmony_ci mbox_t *mbox = (mbox_t *)raw_mbox; 45158c2ecf20Sopenharmony_ci int i; 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci /* Flush adapter cache */ 45188c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 45198c2ecf20Sopenharmony_ci raw_mbox[0] = FLUSH_ADAPTER; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci free_irq(adapter->host->irq, adapter); 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci /* Issue a blocking (interrupts disabled) command to the card */ 45248c2ecf20Sopenharmony_ci issue_scb_block(adapter, raw_mbox); 45258c2ecf20Sopenharmony_ci 45268c2ecf20Sopenharmony_ci /* Flush disks cache */ 45278c2ecf20Sopenharmony_ci memset(&mbox->m_out, 0, sizeof(raw_mbox)); 45288c2ecf20Sopenharmony_ci raw_mbox[0] = FLUSH_SYSTEM; 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci /* Issue a blocking (interrupts disabled) command to the card */ 45318c2ecf20Sopenharmony_ci issue_scb_block(adapter, raw_mbox); 45328c2ecf20Sopenharmony_ci 45338c2ecf20Sopenharmony_ci if (atomic_read(&adapter->pend_cmds) > 0) 45348c2ecf20Sopenharmony_ci dev_warn(&adapter->dev->dev, "pending commands!!\n"); 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_ci /* 45378c2ecf20Sopenharmony_ci * Have a delibrate delay to make sure all the caches are 45388c2ecf20Sopenharmony_ci * actually flushed. 45398c2ecf20Sopenharmony_ci */ 45408c2ecf20Sopenharmony_ci for (i = 0; i <= 10; i++) 45418c2ecf20Sopenharmony_ci mdelay(1000); 45428c2ecf20Sopenharmony_ci} 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_cistatic void 45458c2ecf20Sopenharmony_cimegaraid_remove_one(struct pci_dev *pdev) 45468c2ecf20Sopenharmony_ci{ 45478c2ecf20Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(pdev); 45488c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)host->hostdata; 45498c2ecf20Sopenharmony_ci char buf[12] = { 0 }; 45508c2ecf20Sopenharmony_ci 45518c2ecf20Sopenharmony_ci scsi_remove_host(host); 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci __megaraid_shutdown(adapter); 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci /* Free our resources */ 45568c2ecf20Sopenharmony_ci if (adapter->flag & BOARD_MEMMAP) { 45578c2ecf20Sopenharmony_ci iounmap((void *)adapter->base); 45588c2ecf20Sopenharmony_ci release_mem_region(adapter->host->base, 128); 45598c2ecf20Sopenharmony_ci } else 45608c2ecf20Sopenharmony_ci release_region(adapter->base, 16); 45618c2ecf20Sopenharmony_ci 45628c2ecf20Sopenharmony_ci mega_free_sgl(adapter); 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci sprintf(buf, "hba%d", adapter->host->host_no); 45658c2ecf20Sopenharmony_ci remove_proc_subtree(buf, mega_proc_dir_entry); 45668c2ecf20Sopenharmony_ci 45678c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, MEGA_BUFFER_SIZE, 45688c2ecf20Sopenharmony_ci adapter->mega_buffer, adapter->buf_dma_handle); 45698c2ecf20Sopenharmony_ci kfree(adapter->scb_list); 45708c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, sizeof(mbox64_t), 45718c2ecf20Sopenharmony_ci adapter->una_mbox64, adapter->una_mbox64_dma); 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci scsi_host_put(host); 45748c2ecf20Sopenharmony_ci pci_disable_device(pdev); 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci hba_count--; 45778c2ecf20Sopenharmony_ci} 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_cistatic void 45808c2ecf20Sopenharmony_cimegaraid_shutdown(struct pci_dev *pdev) 45818c2ecf20Sopenharmony_ci{ 45828c2ecf20Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(pdev); 45838c2ecf20Sopenharmony_ci adapter_t *adapter = (adapter_t *)host->hostdata; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci __megaraid_shutdown(adapter); 45868c2ecf20Sopenharmony_ci} 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_cistatic struct pci_device_id megaraid_pci_tbl[] = { 45898c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID, 45908c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 45918c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID2, 45928c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 45938c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_AMI_MEGARAID3, 45948c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 45958c2ecf20Sopenharmony_ci {0,} 45968c2ecf20Sopenharmony_ci}; 45978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, megaraid_pci_tbl); 45988c2ecf20Sopenharmony_ci 45998c2ecf20Sopenharmony_cistatic struct pci_driver megaraid_pci_driver = { 46008c2ecf20Sopenharmony_ci .name = "megaraid_legacy", 46018c2ecf20Sopenharmony_ci .id_table = megaraid_pci_tbl, 46028c2ecf20Sopenharmony_ci .probe = megaraid_probe_one, 46038c2ecf20Sopenharmony_ci .remove = megaraid_remove_one, 46048c2ecf20Sopenharmony_ci .shutdown = megaraid_shutdown, 46058c2ecf20Sopenharmony_ci}; 46068c2ecf20Sopenharmony_ci 46078c2ecf20Sopenharmony_cistatic int __init megaraid_init(void) 46088c2ecf20Sopenharmony_ci{ 46098c2ecf20Sopenharmony_ci int error; 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci if ((max_cmd_per_lun <= 0) || (max_cmd_per_lun > MAX_CMD_PER_LUN)) 46128c2ecf20Sopenharmony_ci max_cmd_per_lun = MAX_CMD_PER_LUN; 46138c2ecf20Sopenharmony_ci if (max_mbox_busy_wait > MBOX_BUSY_WAIT) 46148c2ecf20Sopenharmony_ci max_mbox_busy_wait = MBOX_BUSY_WAIT; 46158c2ecf20Sopenharmony_ci 46168c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 46178c2ecf20Sopenharmony_ci mega_proc_dir_entry = proc_mkdir("megaraid", NULL); 46188c2ecf20Sopenharmony_ci if (!mega_proc_dir_entry) { 46198c2ecf20Sopenharmony_ci printk(KERN_WARNING 46208c2ecf20Sopenharmony_ci "megaraid: failed to create megaraid root\n"); 46218c2ecf20Sopenharmony_ci } 46228c2ecf20Sopenharmony_ci#endif 46238c2ecf20Sopenharmony_ci error = pci_register_driver(&megaraid_pci_driver); 46248c2ecf20Sopenharmony_ci if (error) { 46258c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 46268c2ecf20Sopenharmony_ci remove_proc_entry("megaraid", NULL); 46278c2ecf20Sopenharmony_ci#endif 46288c2ecf20Sopenharmony_ci return error; 46298c2ecf20Sopenharmony_ci } 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci /* 46328c2ecf20Sopenharmony_ci * Register the driver as a character device, for applications 46338c2ecf20Sopenharmony_ci * to access it for ioctls. 46348c2ecf20Sopenharmony_ci * First argument (major) to register_chrdev implies a dynamic 46358c2ecf20Sopenharmony_ci * major number allocation. 46368c2ecf20Sopenharmony_ci */ 46378c2ecf20Sopenharmony_ci major = register_chrdev(0, "megadev_legacy", &megadev_fops); 46388c2ecf20Sopenharmony_ci if (major < 0) { 46398c2ecf20Sopenharmony_ci printk(KERN_WARNING 46408c2ecf20Sopenharmony_ci "megaraid: failed to register char device\n"); 46418c2ecf20Sopenharmony_ci } 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci return 0; 46448c2ecf20Sopenharmony_ci} 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_cistatic void __exit megaraid_exit(void) 46478c2ecf20Sopenharmony_ci{ 46488c2ecf20Sopenharmony_ci /* 46498c2ecf20Sopenharmony_ci * Unregister the character device interface to the driver. 46508c2ecf20Sopenharmony_ci */ 46518c2ecf20Sopenharmony_ci unregister_chrdev(major, "megadev_legacy"); 46528c2ecf20Sopenharmony_ci 46538c2ecf20Sopenharmony_ci pci_unregister_driver(&megaraid_pci_driver); 46548c2ecf20Sopenharmony_ci 46558c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 46568c2ecf20Sopenharmony_ci remove_proc_entry("megaraid", NULL); 46578c2ecf20Sopenharmony_ci#endif 46588c2ecf20Sopenharmony_ci} 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_cimodule_init(megaraid_init); 46618c2ecf20Sopenharmony_cimodule_exit(megaraid_exit); 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_ci/* vi: set ts=8 sw=8 tw=78: */ 4664