blob: ec895d0319f02ff45e5c0387c4c3338438ef92d3 [file] [log] [blame]
Erich Chen1c57e862006-07-12 08:59:32 -07001/*
2*******************************************************************************
3** O.S : Linux
4** FILE NAME : arcmsr_hba.c
Ching Huangaaa64f62014-08-19 15:22:45 +08005** BY : Nick Cheng, C.L. Huang
6** Description: SCSI RAID Device Driver for Areca RAID Controller
Erich Chen1c57e862006-07-12 08:59:32 -07007*******************************************************************************
Ching Huangaaa64f62014-08-19 15:22:45 +08008** Copyright (C) 2002 - 2014, Areca Technology Corporation All rights reserved
Erich Chen1c57e862006-07-12 08:59:32 -07009**
10** Web site: www.areca.com.tw
Nick Cheng1a4f5502007-09-13 17:26:40 +080011** E-mail: support@areca.com.tw
Erich Chen1c57e862006-07-12 08:59:32 -070012**
13** This program is free software; you can redistribute it and/or modify
14** it under the terms of the GNU General Public License version 2 as
15** published by the Free Software Foundation.
16** This program is distributed in the hope that it will be useful,
17** but WITHOUT ANY WARRANTY; without even the implied warranty of
18** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19** GNU General Public License for more details.
20*******************************************************************************
21** Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions
23** are met:
24** 1. Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** 2. Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in the
28** documentation and/or other materials provided with the distribution.
29** 3. The name of the author may not be used to endorse or promote products
30** derived from this software without specific prior written permission.
31**
32** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
33** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
35** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
36** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
37** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
39** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
41** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42*******************************************************************************
43** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
Mauro Carvalho Chehabdade67f2020-03-02 09:16:15 +010044** Firmware Specification, see Documentation/scsi/arcmsr_spec.rst
Erich Chen1c57e862006-07-12 08:59:32 -070045*******************************************************************************
46*/
47#include <linux/module.h>
48#include <linux/reboot.h>
49#include <linux/spinlock.h>
50#include <linux/pci_ids.h>
51#include <linux/interrupt.h>
52#include <linux/moduleparam.h>
53#include <linux/errno.h>
54#include <linux/types.h>
55#include <linux/delay.h>
56#include <linux/dma-mapping.h>
57#include <linux/timer.h>
David Millera7c89622010-08-16 21:20:07 -070058#include <linux/slab.h>
Erich Chen1c57e862006-07-12 08:59:32 -070059#include <linux/pci.h>
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +080060#include <linux/aer.h>
Ching Huang2e9feb42014-09-24 17:33:34 +080061#include <linux/circ_buf.h>
Erich Chen1c57e862006-07-12 08:59:32 -070062#include <asm/dma.h>
63#include <asm/io.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080064#include <linux/uaccess.h>
Erich Chen1c57e862006-07-12 08:59:32 -070065#include <scsi/scsi_host.h>
66#include <scsi/scsi.h>
67#include <scsi/scsi_cmnd.h>
68#include <scsi/scsi_tcq.h>
69#include <scsi/scsi_device.h>
70#include <scsi/scsi_transport.h>
71#include <scsi/scsicam.h>
72#include "arcmsr.h"
Ching Huangaaa64f62014-08-19 15:22:45 +080073MODULE_AUTHOR("Nick Cheng, C.L. Huang <support@areca.com.tw>");
74MODULE_DESCRIPTION("Areca ARC11xx/12xx/16xx/188x SAS/SATA RAID Controller Driver");
Erich Chen1c57e862006-07-12 08:59:32 -070075MODULE_LICENSE("Dual BSD/GPL");
76MODULE_VERSION(ARCMSR_DRIVER_VERSION);
Tomas Henzl8b7eb862011-04-29 16:28:24 +020077
Ching Huang07640402017-12-05 10:26:38 +080078static int msix_enable = 1;
79module_param(msix_enable, int, S_IRUGO);
80MODULE_PARM_DESC(msix_enable, "Enable MSI-X interrupt(0 ~ 1), msix_enable=1(enable), =0(disable)");
81
Ching Huanga18686e2017-12-05 10:24:01 +080082static int msi_enable = 1;
83module_param(msi_enable, int, S_IRUGO);
84MODULE_PARM_DESC(msi_enable, "Enable MSI interrupt(0 ~ 1), msi_enable=1(enable), =0(disable)");
85
Ching Huangdd6206e2017-12-05 09:47:44 +080086static int host_can_queue = ARCMSR_DEFAULT_OUTSTANDING_CMD;
87module_param(host_can_queue, int, S_IRUGO);
88MODULE_PARM_DESC(host_can_queue, " adapter queue depth(32 ~ 1024), default is 128");
89
Ching Huangabf33d82017-12-05 09:55:02 +080090static int cmd_per_lun = ARCMSR_DEFAULT_CMD_PERLUN;
91module_param(cmd_per_lun, int, S_IRUGO);
92MODULE_PARM_DESC(cmd_per_lun, " device queue depth(1 ~ 128), default is 32");
93
Ching Huang7ec72612018-12-19 16:53:44 +080094static int dma_mask_64 = 0;
95module_param(dma_mask_64, int, S_IRUGO);
96MODULE_PARM_DESC(dma_mask_64, " set DMA mask to 64 bits(0 ~ 1), dma_mask_64=1(64 bits), =0(32 bits)");
97
Ching Huangb416c092017-12-05 09:59:52 +080098static int set_date_time = 0;
99module_param(set_date_time, int, S_IRUGO);
100MODULE_PARM_DESC(set_date_time, " send date, time to iop(0 ~ 1), set_date_time=1(enable), default(=0) is disable");
101
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200102#define ARCMSR_SLEEPTIME 10
103#define ARCMSR_RETRYCOUNT 12
104
Ching Huangc10b1d52014-08-19 15:20:31 +0800105static wait_queue_head_t wait_q;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800106static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
107 struct scsi_cmnd *cmd);
108static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700109static int arcmsr_abort(struct scsi_cmnd *);
110static int arcmsr_bus_reset(struct scsi_cmnd *);
111static int arcmsr_bios_param(struct scsi_device *sdev,
Nick Cheng1a4f5502007-09-13 17:26:40 +0800112 struct block_device *bdev, sector_t capacity, int *info);
Jeff Garzikf2812332010-11-16 02:10:29 -0500113static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
Erich Chen1c57e862006-07-12 08:59:32 -0700114static int arcmsr_probe(struct pci_dev *pdev,
115 const struct pci_device_id *id);
Ching Huang61cda872014-08-19 14:26:09 +0800116static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state);
117static int arcmsr_resume(struct pci_dev *pdev);
Erich Chen1c57e862006-07-12 08:59:32 -0700118static void arcmsr_remove(struct pci_dev *pdev);
119static void arcmsr_shutdown(struct pci_dev *pdev);
120static void arcmsr_iop_init(struct AdapterControlBlock *acb);
121static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800122static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
Ching Huang61cda872014-08-19 14:26:09 +0800123static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
124 u32 intmask_org);
Erich Chen1c57e862006-07-12 08:59:32 -0700125static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
Ching Huang626fa322014-08-19 15:10:12 +0800126static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb);
127static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb);
Kees Cooke99e88a2017-10-16 14:43:17 -0700128static void arcmsr_request_device_map(struct timer_list *t);
Nick Cheng36b83de2010-05-17 11:22:42 +0800129static void arcmsr_message_isr_bh_fn(struct work_struct *work);
Nick Chengae52e7f2010-06-18 15:39:12 +0800130static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
Nick Cheng36b83de2010-05-17 11:22:42 +0800131static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
Ching Huang626fa322014-08-19 15:10:12 +0800132static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *pACB);
Ching Huang5b374792014-08-19 15:25:22 +0800133static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb);
Ching Huang23509022017-12-05 09:35:34 +0800134static void arcmsr_hbaE_message_isr(struct AdapterControlBlock *acb);
135static void arcmsr_hbaE_postqueue_isr(struct AdapterControlBlock *acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800136static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700137static const char *arcmsr_info(struct Scsi_Host *);
138static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
Ching Huangb4eb6ae2014-08-19 15:28:36 +0800139static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
Ching Huang7e315ff2015-11-25 19:49:33 +0800140static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
Ching Huangb416c092017-12-05 09:59:52 +0800141static void arcmsr_set_iop_datetime(struct timer_list *);
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +0100142static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
Erich Chen1c57e862006-07-12 08:59:32 -0700143{
144 if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
145 queue_depth = ARCMSR_MAX_CMD_PERLUN;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +0100146 return scsi_change_queue_depth(sdev, queue_depth);
Erich Chen1c57e862006-07-12 08:59:32 -0700147}
148
149static struct scsi_host_template arcmsr_scsi_host_template = {
150 .module = THIS_MODULE,
Ching Huangaaa64f62014-08-19 15:22:45 +0800151 .name = "Areca SAS/SATA RAID driver",
Erich Chen1c57e862006-07-12 08:59:32 -0700152 .info = arcmsr_info,
153 .queuecommand = arcmsr_queue_command,
Ching Huanga3de4b52017-12-05 10:16:13 +0800154 .eh_abort_handler = arcmsr_abort,
Erich Chen1c57e862006-07-12 08:59:32 -0700155 .eh_bus_reset_handler = arcmsr_bus_reset,
156 .bios_param = arcmsr_bios_param,
157 .change_queue_depth = arcmsr_adjust_disk_queue_depth,
Ching Huangdd6206e2017-12-05 09:47:44 +0800158 .can_queue = ARCMSR_DEFAULT_OUTSTANDING_CMD,
Ching Huanga3de4b52017-12-05 10:16:13 +0800159 .this_id = ARCMSR_SCSI_INITIATOR_ID,
160 .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES,
161 .max_sectors = ARCMSR_MAX_XFER_SECTORS_C,
Ching Huangabf33d82017-12-05 09:55:02 +0800162 .cmd_per_lun = ARCMSR_DEFAULT_CMD_PERLUN,
Erich Chen1c57e862006-07-12 08:59:32 -0700163 .shost_attrs = arcmsr_host_attrs,
Martin K. Petersen54b2b502013-10-23 06:25:40 -0400164 .no_write_same = 1,
Erich Chen1c57e862006-07-12 08:59:32 -0700165};
Ching Huang8b7c9942014-08-19 14:55:57 +0800166
Erich Chen1c57e862006-07-12 08:59:32 -0700167static struct pci_device_id arcmsr_device_id_table[] = {
Ching Huang8b7c9942014-08-19 14:55:57 +0800168 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110),
169 .driver_data = ACB_ADAPTER_TYPE_A},
170 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120),
171 .driver_data = ACB_ADAPTER_TYPE_A},
172 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130),
173 .driver_data = ACB_ADAPTER_TYPE_A},
174 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160),
175 .driver_data = ACB_ADAPTER_TYPE_A},
176 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170),
177 .driver_data = ACB_ADAPTER_TYPE_A},
178 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200),
179 .driver_data = ACB_ADAPTER_TYPE_B},
180 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201),
181 .driver_data = ACB_ADAPTER_TYPE_B},
182 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
183 .driver_data = ACB_ADAPTER_TYPE_B},
Ching Huang7e315ff2015-11-25 19:49:33 +0800184 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
185 .driver_data = ACB_ADAPTER_TYPE_B},
Ching Huang8b7c9942014-08-19 14:55:57 +0800186 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
187 .driver_data = ACB_ADAPTER_TYPE_A},
Ching Huang5b374792014-08-19 15:25:22 +0800188 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
189 .driver_data = ACB_ADAPTER_TYPE_D},
Ching Huang8b7c9942014-08-19 14:55:57 +0800190 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220),
191 .driver_data = ACB_ADAPTER_TYPE_A},
192 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230),
193 .driver_data = ACB_ADAPTER_TYPE_A},
194 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260),
195 .driver_data = ACB_ADAPTER_TYPE_A},
196 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270),
197 .driver_data = ACB_ADAPTER_TYPE_A},
198 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280),
199 .driver_data = ACB_ADAPTER_TYPE_A},
200 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380),
201 .driver_data = ACB_ADAPTER_TYPE_A},
202 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381),
203 .driver_data = ACB_ADAPTER_TYPE_A},
204 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680),
205 .driver_data = ACB_ADAPTER_TYPE_A},
206 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681),
207 .driver_data = ACB_ADAPTER_TYPE_A},
208 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880),
209 .driver_data = ACB_ADAPTER_TYPE_C},
Ching Huang23509022017-12-05 09:35:34 +0800210 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1884),
211 .driver_data = ACB_ADAPTER_TYPE_E},
Erich Chen1c57e862006-07-12 08:59:32 -0700212 {0, 0}, /* Terminating entry */
213};
214MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
Ching Huang8b7c9942014-08-19 14:55:57 +0800215
Erich Chen1c57e862006-07-12 08:59:32 -0700216static struct pci_driver arcmsr_pci_driver = {
217 .name = "arcmsr",
Ching Huanga3de4b52017-12-05 10:16:13 +0800218 .id_table = arcmsr_device_id_table,
Erich Chen1c57e862006-07-12 08:59:32 -0700219 .probe = arcmsr_probe,
220 .remove = arcmsr_remove,
Ching Huang61cda872014-08-19 14:26:09 +0800221 .suspend = arcmsr_suspend,
222 .resume = arcmsr_resume,
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +0800223 .shutdown = arcmsr_shutdown,
Erich Chen1c57e862006-07-12 08:59:32 -0700224};
Nick Chengcdd3cb12010-07-13 20:03:04 +0800225/*
226****************************************************************************
227****************************************************************************
228*/
Nick Chengcdd3cb12010-07-13 20:03:04 +0800229
Ching Huang609d0852018-12-19 16:27:20 +0800230static void arcmsr_free_io_queue(struct AdapterControlBlock *acb)
Nick Chengae52e7f2010-06-18 15:39:12 +0800231{
232 switch (acb->adapter_type) {
Ching Huang5b374792014-08-19 15:25:22 +0800233 case ACB_ADAPTER_TYPE_B:
Ching Huang23509022017-12-05 09:35:34 +0800234 case ACB_ADAPTER_TYPE_D:
235 case ACB_ADAPTER_TYPE_E: {
Ching Huang381d66d2018-12-19 16:24:03 +0800236 dma_free_coherent(&acb->pdev->dev, acb->ioqueue_size,
Ching Huang6e38adf2014-08-19 15:14:14 +0800237 acb->dma_coherent2, acb->dma_coherent_handle2);
238 break;
Nick Chengae52e7f2010-06-18 15:39:12 +0800239 }
240 }
241}
242
243static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
244{
245 struct pci_dev *pdev = acb->pdev;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800246 switch (acb->adapter_type){
Nick Chengae52e7f2010-06-18 15:39:12 +0800247 case ACB_ADAPTER_TYPE_A:{
Nick Chengcdd3cb12010-07-13 20:03:04 +0800248 acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0));
Nick Chengae52e7f2010-06-18 15:39:12 +0800249 if (!acb->pmuA) {
250 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
251 return false;
252 }
253 break;
254 }
255 case ACB_ADAPTER_TYPE_B:{
256 void __iomem *mem_base0, *mem_base1;
257 mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
258 if (!mem_base0) {
259 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
260 return false;
261 }
262 mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
263 if (!mem_base1) {
264 iounmap(mem_base0);
265 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
266 return false;
267 }
268 acb->mem_base0 = mem_base0;
269 acb->mem_base1 = mem_base1;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800270 break;
271 }
272 case ACB_ADAPTER_TYPE_C:{
Christoph Hellwig4bdc0d62020-01-06 09:43:50 +0100273 acb->pmuC = ioremap(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
Nick Chengcdd3cb12010-07-13 20:03:04 +0800274 if (!acb->pmuC) {
275 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
276 return false;
277 }
278 if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
279 writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
280 return true;
281 }
282 break;
Nick Chengae52e7f2010-06-18 15:39:12 +0800283 }
Ching Huang5b374792014-08-19 15:25:22 +0800284 case ACB_ADAPTER_TYPE_D: {
285 void __iomem *mem_base0;
Lee Jones18bc4352020-07-13 08:46:30 +0100286 unsigned long addr, range;
Ching Huang5b374792014-08-19 15:25:22 +0800287
288 addr = (unsigned long)pci_resource_start(pdev, 0);
289 range = pci_resource_len(pdev, 0);
Dan Williams92b19ff2015-08-10 23:07:06 -0400290 mem_base0 = ioremap(addr, range);
Ching Huang5b374792014-08-19 15:25:22 +0800291 if (!mem_base0) {
292 pr_notice("arcmsr%d: memory mapping region fail\n",
293 acb->host->host_no);
294 return false;
295 }
296 acb->mem_base0 = mem_base0;
297 break;
298 }
Ching Huang23509022017-12-05 09:35:34 +0800299 case ACB_ADAPTER_TYPE_E: {
300 acb->pmuE = ioremap(pci_resource_start(pdev, 1),
301 pci_resource_len(pdev, 1));
302 if (!acb->pmuE) {
303 pr_notice("arcmsr%d: memory mapping region fail \n",
304 acb->host->host_no);
305 return false;
306 }
307 writel(0, &acb->pmuE->host_int_status); /*clear interrupt*/
308 writel(ARCMSR_HBEMU_DOORBELL_SYNC, &acb->pmuE->iobound_doorbell); /* synchronize doorbell to 0 */
309 acb->in_doorbell = 0;
310 acb->out_doorbell = 0;
311 break;
312 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800313 }
314 return true;
315}
316
317static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
318{
319 switch (acb->adapter_type) {
Nick Chengcdd3cb12010-07-13 20:03:04 +0800320 case ACB_ADAPTER_TYPE_A:{
321 iounmap(acb->pmuA);
322 }
323 break;
324 case ACB_ADAPTER_TYPE_B:{
325 iounmap(acb->mem_base0);
326 iounmap(acb->mem_base1);
327 }
328
329 break;
330 case ACB_ADAPTER_TYPE_C:{
331 iounmap(acb->pmuC);
332 }
Ching Huang5b374792014-08-19 15:25:22 +0800333 break;
334 case ACB_ADAPTER_TYPE_D:
335 iounmap(acb->mem_base0);
336 break;
Ching Huang23509022017-12-05 09:35:34 +0800337 case ACB_ADAPTER_TYPE_E:
338 iounmap(acb->pmuE);
339 break;
Nick Chengae52e7f2010-06-18 15:39:12 +0800340 }
341}
342
David Howells7d12e782006-10-05 14:55:46 +0100343static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
Erich Chen1c57e862006-07-12 08:59:32 -0700344{
345 irqreturn_t handle_state;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800346 struct AdapterControlBlock *acb = dev_id;
Erich Chen1c57e862006-07-12 08:59:32 -0700347
Erich Chen1c57e862006-07-12 08:59:32 -0700348 handle_state = arcmsr_interrupt(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700349 return handle_state;
350}
351
352static int arcmsr_bios_param(struct scsi_device *sdev,
353 struct block_device *bdev, sector_t capacity, int *geom)
354{
Christoph Hellwiga10183d2020-03-24 08:25:17 +0100355 int heads, sectors, cylinders, total_capacity;
Erich Chen1c57e862006-07-12 08:59:32 -0700356
Christoph Hellwiga10183d2020-03-24 08:25:17 +0100357 if (scsi_partsize(bdev, capacity, geom))
358 return 0;
359
Erich Chen1c57e862006-07-12 08:59:32 -0700360 total_capacity = capacity;
361 heads = 64;
362 sectors = 32;
363 cylinders = total_capacity / (heads * sectors);
364 if (cylinders > 1024) {
365 heads = 255;
366 sectors = 63;
367 cylinders = total_capacity / (heads * sectors);
368 }
369 geom[0] = heads;
370 geom[1] = sectors;
371 geom[2] = cylinders;
372 return 0;
373}
374
Ching Huang626fa322014-08-19 15:10:12 +0800375static uint8_t arcmsr_hbaA_wait_msgint_ready(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800376{
Nick Chengae52e7f2010-06-18 15:39:12 +0800377 struct MessageUnit_A __iomem *reg = acb->pmuA;
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200378 int i;
Nick Chengae52e7f2010-06-18 15:39:12 +0800379
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200380 for (i = 0; i < 2000; i++) {
381 if (readl(&reg->outbound_intstatus) &
382 ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
383 writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
384 &reg->outbound_intstatus);
385 return true;
386 }
387 msleep(10);
388 } /* max 20 seconds */
389
Nick Chengcdd3cb12010-07-13 20:03:04 +0800390 return false;
Nick Chengae52e7f2010-06-18 15:39:12 +0800391}
392
Ching Huang626fa322014-08-19 15:10:12 +0800393static uint8_t arcmsr_hbaB_wait_msgint_ready(struct AdapterControlBlock *acb)
Nick Chengae52e7f2010-06-18 15:39:12 +0800394{
395 struct MessageUnit_B *reg = acb->pmuB;
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200396 int i;
Nick Chengae52e7f2010-06-18 15:39:12 +0800397
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200398 for (i = 0; i < 2000; i++) {
399 if (readl(reg->iop2drv_doorbell)
400 & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
401 writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN,
402 reg->iop2drv_doorbell);
403 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT,
404 reg->drv2iop_doorbell);
405 return true;
406 }
407 msleep(10);
408 } /* max 20 seconds */
409
Nick Chengcdd3cb12010-07-13 20:03:04 +0800410 return false;
Nick Chengae52e7f2010-06-18 15:39:12 +0800411}
412
Ching Huang626fa322014-08-19 15:10:12 +0800413static uint8_t arcmsr_hbaC_wait_msgint_ready(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +0800414{
Ching Huangc10b1d52014-08-19 15:20:31 +0800415 struct MessageUnit_C __iomem *phbcmu = pACB->pmuC;
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200416 int i;
417
418 for (i = 0; i < 2000; i++) {
419 if (readl(&phbcmu->outbound_doorbell)
420 & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
421 writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
422 &phbcmu->outbound_doorbell_clear); /*clear interrupt*/
423 return true;
424 }
425 msleep(10);
426 } /* max 20 seconds */
427
Nick Chengcdd3cb12010-07-13 20:03:04 +0800428 return false;
429}
Tomas Henzl8b7eb862011-04-29 16:28:24 +0200430
Ching Huang5b374792014-08-19 15:25:22 +0800431static bool arcmsr_hbaD_wait_msgint_ready(struct AdapterControlBlock *pACB)
432{
433 struct MessageUnit_D *reg = pACB->pmuD;
434 int i;
435
436 for (i = 0; i < 2000; i++) {
437 if (readl(reg->outbound_doorbell)
438 & ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
439 writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
440 reg->outbound_doorbell);
441 return true;
442 }
443 msleep(10);
444 } /* max 20 seconds */
445 return false;
446}
447
Ching Huang23509022017-12-05 09:35:34 +0800448static bool arcmsr_hbaE_wait_msgint_ready(struct AdapterControlBlock *pACB)
449{
450 int i;
451 uint32_t read_doorbell;
452 struct MessageUnit_E __iomem *phbcmu = pACB->pmuE;
453
454 for (i = 0; i < 2000; i++) {
455 read_doorbell = readl(&phbcmu->iobound_doorbell);
456 if ((read_doorbell ^ pACB->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
457 writel(0, &phbcmu->host_int_status); /*clear interrupt*/
458 pACB->in_doorbell = read_doorbell;
459 return true;
460 }
461 msleep(10);
462 } /* max 20 seconds */
463 return false;
464}
465
Ching Huang626fa322014-08-19 15:10:12 +0800466static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb)
Nick Chengae52e7f2010-06-18 15:39:12 +0800467{
468 struct MessageUnit_A __iomem *reg = acb->pmuA;
469 int retry_count = 30;
Nick Chengae52e7f2010-06-18 15:39:12 +0800470 writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
471 do {
Ching Huang626fa322014-08-19 15:10:12 +0800472 if (arcmsr_hbaA_wait_msgint_ready(acb))
Nick Chengae52e7f2010-06-18 15:39:12 +0800473 break;
474 else {
475 retry_count--;
476 printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
477 timeout, retry count down = %d \n", acb->host->host_no, retry_count);
478 }
479 } while (retry_count != 0);
480}
481
Ching Huang626fa322014-08-19 15:10:12 +0800482static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb)
Nick Chengae52e7f2010-06-18 15:39:12 +0800483{
484 struct MessageUnit_B *reg = acb->pmuB;
485 int retry_count = 30;
Nick Chengae52e7f2010-06-18 15:39:12 +0800486 writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
487 do {
Ching Huang626fa322014-08-19 15:10:12 +0800488 if (arcmsr_hbaB_wait_msgint_ready(acb))
Nick Chengae52e7f2010-06-18 15:39:12 +0800489 break;
490 else {
491 retry_count--;
492 printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
493 timeout,retry count down = %d \n", acb->host->host_no, retry_count);
494 }
495 } while (retry_count != 0);
496}
497
Ching Huang626fa322014-08-19 15:10:12 +0800498static void arcmsr_hbaC_flush_cache(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +0800499{
Ching Huangc10b1d52014-08-19 15:20:31 +0800500 struct MessageUnit_C __iomem *reg = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800501 int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
502 writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
503 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
504 do {
Ching Huang626fa322014-08-19 15:10:12 +0800505 if (arcmsr_hbaC_wait_msgint_ready(pACB)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +0800506 break;
507 } else {
508 retry_count--;
509 printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
510 timeout,retry count down = %d \n", pACB->host->host_no, retry_count);
511 }
512 } while (retry_count != 0);
513 return;
514}
Ching Huang5b374792014-08-19 15:25:22 +0800515
516static void arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB)
517{
518 int retry_count = 15;
519 struct MessageUnit_D *reg = pACB->pmuD;
520
521 writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, reg->inbound_msgaddr0);
522 do {
523 if (arcmsr_hbaD_wait_msgint_ready(pACB))
524 break;
525
526 retry_count--;
527 pr_notice("arcmsr%d: wait 'flush adapter "
528 "cache' timeout, retry count down = %d\n",
529 pACB->host->host_no, retry_count);
530 } while (retry_count != 0);
531}
532
Ching Huang23509022017-12-05 09:35:34 +0800533static void arcmsr_hbaE_flush_cache(struct AdapterControlBlock *pACB)
534{
535 int retry_count = 30;
536 struct MessageUnit_E __iomem *reg = pACB->pmuE;
537
538 writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
539 pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
540 writel(pACB->out_doorbell, &reg->iobound_doorbell);
541 do {
542 if (arcmsr_hbaE_wait_msgint_ready(pACB))
543 break;
544 retry_count--;
545 pr_notice("arcmsr%d: wait 'flush adapter "
546 "cache' timeout, retry count down = %d\n",
547 pACB->host->host_no, retry_count);
548 } while (retry_count != 0);
549}
550
Nick Chengae52e7f2010-06-18 15:39:12 +0800551static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
552{
Nick Cheng1a4f5502007-09-13 17:26:40 +0800553 switch (acb->adapter_type) {
554
555 case ACB_ADAPTER_TYPE_A: {
Ching Huang626fa322014-08-19 15:10:12 +0800556 arcmsr_hbaA_flush_cache(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800557 }
558 break;
559
560 case ACB_ADAPTER_TYPE_B: {
Ching Huang626fa322014-08-19 15:10:12 +0800561 arcmsr_hbaB_flush_cache(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +0800562 }
Nick Chengcdd3cb12010-07-13 20:03:04 +0800563 break;
564 case ACB_ADAPTER_TYPE_C: {
Ching Huang626fa322014-08-19 15:10:12 +0800565 arcmsr_hbaC_flush_cache(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800566 }
Ching Huang5b374792014-08-19 15:25:22 +0800567 break;
568 case ACB_ADAPTER_TYPE_D:
569 arcmsr_hbaD_flush_cache(acb);
570 break;
Ching Huang23509022017-12-05 09:35:34 +0800571 case ACB_ADAPTER_TYPE_E:
572 arcmsr_hbaE_flush_cache(acb);
573 break;
Nick Chengae52e7f2010-06-18 15:39:12 +0800574 }
575}
Nick Cheng1a4f5502007-09-13 17:26:40 +0800576
Ching Huang222f1182018-12-19 16:31:00 +0800577static void arcmsr_hbaB_assign_regAddr(struct AdapterControlBlock *acb)
578{
579 struct MessageUnit_B *reg = acb->pmuB;
580
581 if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
582 reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
583 reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
584 reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
585 reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
586 } else {
587 reg->drv2iop_doorbell= MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
588 reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
589 reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
590 reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
591 }
592 reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
593 reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
594 reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
595}
596
597static void arcmsr_hbaD_assign_regAddr(struct AdapterControlBlock *acb)
598{
599 struct MessageUnit_D *reg = acb->pmuD;
600
601 reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
602 reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
603 reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
604 reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
605 reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
606 reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
607 reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
608 reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
609 reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
610 reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
611 reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
612 reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
613 reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
614 reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
615 reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
616 reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
617 reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
618 reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
619 reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
620 reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
621 reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
622 reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
623 reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
624 reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
625 reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
626 reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
627}
628
Ching Huang02040672015-11-26 19:41:15 +0800629static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
630{
631 bool rtn = true;
632 void *dma_coherent;
633 dma_addr_t dma_coherent_handle;
634 struct pci_dev *pdev = acb->pdev;
635
636 switch (acb->adapter_type) {
637 case ACB_ADAPTER_TYPE_B: {
Ching Huang381d66d2018-12-19 16:24:03 +0800638 acb->ioqueue_size = roundup(sizeof(struct MessageUnit_B), 32);
Ching Huang3e3153b2019-01-18 10:53:41 +0800639 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->ioqueue_size,
Ching Huang02040672015-11-26 19:41:15 +0800640 &dma_coherent_handle, GFP_KERNEL);
641 if (!dma_coherent) {
642 pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
643 return false;
644 }
645 acb->dma_coherent_handle2 = dma_coherent_handle;
646 acb->dma_coherent2 = dma_coherent;
Ching Huang222f1182018-12-19 16:31:00 +0800647 acb->pmuB = (struct MessageUnit_B *)dma_coherent;
648 arcmsr_hbaB_assign_regAddr(acb);
Ching Huang02040672015-11-26 19:41:15 +0800649 }
650 break;
651 case ACB_ADAPTER_TYPE_D: {
Ching Huang381d66d2018-12-19 16:24:03 +0800652 acb->ioqueue_size = roundup(sizeof(struct MessageUnit_D), 32);
Ching Huang3e3153b2019-01-18 10:53:41 +0800653 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->ioqueue_size,
Ching Huang02040672015-11-26 19:41:15 +0800654 &dma_coherent_handle, GFP_KERNEL);
655 if (!dma_coherent) {
656 pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
657 return false;
658 }
659 acb->dma_coherent_handle2 = dma_coherent_handle;
660 acb->dma_coherent2 = dma_coherent;
Ching Huang222f1182018-12-19 16:31:00 +0800661 acb->pmuD = (struct MessageUnit_D *)dma_coherent;
662 arcmsr_hbaD_assign_regAddr(acb);
Ching Huang02040672015-11-26 19:41:15 +0800663 }
664 break;
Ching Huang23509022017-12-05 09:35:34 +0800665 case ACB_ADAPTER_TYPE_E: {
666 uint32_t completeQ_size;
667 completeQ_size = sizeof(struct deliver_completeQ) * ARCMSR_MAX_HBE_DONEQUEUE + 128;
Ching Huang381d66d2018-12-19 16:24:03 +0800668 acb->ioqueue_size = roundup(completeQ_size, 32);
Ching Huang3e3153b2019-01-18 10:53:41 +0800669 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->ioqueue_size,
Ching Huang23509022017-12-05 09:35:34 +0800670 &dma_coherent_handle, GFP_KERNEL);
671 if (!dma_coherent){
672 pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
673 return false;
674 }
675 acb->dma_coherent_handle2 = dma_coherent_handle;
676 acb->dma_coherent2 = dma_coherent;
677 acb->pCompletionQ = dma_coherent;
Ching Huang381d66d2018-12-19 16:24:03 +0800678 acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ);
Ching Huang23509022017-12-05 09:35:34 +0800679 acb->doneq_index = 0;
680 }
681 break;
Ching Huang02040672015-11-26 19:41:15 +0800682 default:
683 break;
684 }
685 return rtn;
686}
687
Nick Chengae52e7f2010-06-18 15:39:12 +0800688static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
689{
Nick Chengcdd3cb12010-07-13 20:03:04 +0800690 struct pci_dev *pdev = acb->pdev;
691 void *dma_coherent;
692 dma_addr_t dma_coherent_handle;
693 struct CommandControlBlock *ccb_tmp;
694 int i = 0, j = 0;
Ching Huang7860a482018-12-19 16:34:58 +0800695 unsigned long cdb_phyaddr, next_ccb_phy;
Tomas Henzl87f76152011-04-29 16:28:30 +0200696 unsigned long roundup_ccbsize;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800697 unsigned long max_xfer_len;
698 unsigned long max_sg_entrys;
Ching Huang7860a482018-12-19 16:34:58 +0800699 uint32_t firm_config_version, curr_phy_upper32;
Tomas Henzl87f76152011-04-29 16:28:30 +0200700
Nick Chengcdd3cb12010-07-13 20:03:04 +0800701 for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
702 for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
703 acb->devstate[i][j] = ARECA_RAID_GONE;
Nick Chengae52e7f2010-06-18 15:39:12 +0800704
Nick Chengcdd3cb12010-07-13 20:03:04 +0800705 max_xfer_len = ARCMSR_MAX_XFER_LEN;
706 max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
707 firm_config_version = acb->firm_cfg_version;
708 if((firm_config_version & 0xFF) >= 3){
709 max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
Tomas Henzl87f76152011-04-29 16:28:30 +0200710 max_sg_entrys = (max_xfer_len/4096);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800711 }
712 acb->host->max_sectors = max_xfer_len/512;
713 acb->host->sg_tablesize = max_sg_entrys;
714 roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
Ching Huangd076e4a2017-12-05 09:44:23 +0800715 acb->uncache_size = roundup_ccbsize * acb->maxFreeCCB;
Ching Huang222f1182018-12-19 16:31:00 +0800716 acb->uncache_size += acb->ioqueue_size;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800717 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
718 if(!dma_coherent){
Tomas Henzl87f76152011-04-29 16:28:30 +0200719 printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800720 return -ENOMEM;
721 }
722 acb->dma_coherent = dma_coherent;
723 acb->dma_coherent_handle = dma_coherent_handle;
724 memset(dma_coherent, 0, acb->uncache_size);
Ching Huang23509022017-12-05 09:35:34 +0800725 acb->ccbsize = roundup_ccbsize;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800726 ccb_tmp = dma_coherent;
Ching Huang7860a482018-12-19 16:34:58 +0800727 curr_phy_upper32 = upper_32_bits(dma_coherent_handle);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800728 acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
Ching Huangd076e4a2017-12-05 09:44:23 +0800729 for(i = 0; i < acb->maxFreeCCB; i++){
Ching Huang7860a482018-12-19 16:34:58 +0800730 cdb_phyaddr = (unsigned long)dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
Ching Huang5b374792014-08-19 15:25:22 +0800731 switch (acb->adapter_type) {
732 case ACB_ADAPTER_TYPE_A:
733 case ACB_ADAPTER_TYPE_B:
734 ccb_tmp->cdb_phyaddr = cdb_phyaddr >> 5;
735 break;
736 case ACB_ADAPTER_TYPE_C:
737 case ACB_ADAPTER_TYPE_D:
Ching Huang23509022017-12-05 09:35:34 +0800738 case ACB_ADAPTER_TYPE_E:
Ching Huang5b374792014-08-19 15:25:22 +0800739 ccb_tmp->cdb_phyaddr = cdb_phyaddr;
740 break;
741 }
Nick Chengcdd3cb12010-07-13 20:03:04 +0800742 acb->pccb_pool[i] = ccb_tmp;
743 ccb_tmp->acb = acb;
Ching Huang23509022017-12-05 09:35:34 +0800744 ccb_tmp->smid = (u32)i << 16;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800745 INIT_LIST_HEAD(&ccb_tmp->list);
Ching Huang7860a482018-12-19 16:34:58 +0800746 next_ccb_phy = dma_coherent_handle + roundup_ccbsize;
747 if (upper_32_bits(next_ccb_phy) != curr_phy_upper32) {
748 acb->maxFreeCCB = i;
749 acb->host->can_queue = i;
750 break;
751 }
752 else
753 list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800754 ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
Ching Huang7860a482018-12-19 16:34:58 +0800755 dma_coherent_handle = next_ccb_phy;
Erich Chen1c57e862006-07-12 08:59:32 -0700756 }
Ching Huang222f1182018-12-19 16:31:00 +0800757 acb->dma_coherent_handle2 = dma_coherent_handle;
758 acb->dma_coherent2 = ccb_tmp;
759 switch (acb->adapter_type) {
760 case ACB_ADAPTER_TYPE_B:
761 acb->pmuB = (struct MessageUnit_B *)acb->dma_coherent2;
762 arcmsr_hbaB_assign_regAddr(acb);
763 break;
764 case ACB_ADAPTER_TYPE_D:
765 acb->pmuD = (struct MessageUnit_D *)acb->dma_coherent2;
766 arcmsr_hbaD_assign_regAddr(acb);
767 break;
768 case ACB_ADAPTER_TYPE_E:
769 acb->pCompletionQ = acb->dma_coherent2;
770 acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ);
771 acb->doneq_index = 0;
772 break;
773 }
Erich Chen1c57e862006-07-12 08:59:32 -0700774 return 0;
775}
Nick Cheng36b83de2010-05-17 11:22:42 +0800776
Nick Chengcdd3cb12010-07-13 20:03:04 +0800777static void arcmsr_message_isr_bh_fn(struct work_struct *work)
778{
Ching Huang12aad942014-08-19 14:59:00 +0800779 struct AdapterControlBlock *acb = container_of(work,
780 struct AdapterControlBlock, arcmsr_do_message_isr_bh);
781 char *acb_dev_map = (char *)acb->device_map;
782 uint32_t __iomem *signature = NULL;
783 char __iomem *devicemap = NULL;
784 int target, lun;
785 struct scsi_device *psdev;
786 char diff, temp;
787
Ching Huang5dd8b3e2017-12-05 09:57:23 +0800788 acb->acb_flags &= ~ACB_F_MSG_GET_CONFIG;
Nick Cheng36b83de2010-05-17 11:22:42 +0800789 switch (acb->adapter_type) {
Ching Huang12aad942014-08-19 14:59:00 +0800790 case ACB_ADAPTER_TYPE_A: {
791 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +0800792
Ching Huang12aad942014-08-19 14:59:00 +0800793 signature = (uint32_t __iomem *)(&reg->message_rwbuffer[0]);
794 devicemap = (char __iomem *)(&reg->message_rwbuffer[21]);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800795 break;
Ching Huang12aad942014-08-19 14:59:00 +0800796 }
797 case ACB_ADAPTER_TYPE_B: {
798 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng36b83de2010-05-17 11:22:42 +0800799
Ching Huang12aad942014-08-19 14:59:00 +0800800 signature = (uint32_t __iomem *)(&reg->message_rwbuffer[0]);
801 devicemap = (char __iomem *)(&reg->message_rwbuffer[21]);
802 break;
803 }
804 case ACB_ADAPTER_TYPE_C: {
805 struct MessageUnit_C __iomem *reg = acb->pmuC;
806
807 signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
808 devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
809 break;
810 }
Ching Huang5b374792014-08-19 15:25:22 +0800811 case ACB_ADAPTER_TYPE_D: {
812 struct MessageUnit_D *reg = acb->pmuD;
813
814 signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
815 devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
816 break;
817 }
Ching Huang23509022017-12-05 09:35:34 +0800818 case ACB_ADAPTER_TYPE_E: {
819 struct MessageUnit_E __iomem *reg = acb->pmuE;
820
821 signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
822 devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
823 break;
824 }
Ching Huang12aad942014-08-19 14:59:00 +0800825 }
826 atomic_inc(&acb->rq_map_token);
827 if (readl(signature) != ARCMSR_SIGNATURE_GET_CONFIG)
828 return;
829 for (target = 0; target < ARCMSR_MAX_TARGETID - 1;
830 target++) {
831 temp = readb(devicemap);
832 diff = (*acb_dev_map) ^ temp;
833 if (diff != 0) {
834 *acb_dev_map = temp;
835 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN;
836 lun++) {
837 if ((diff & 0x01) == 1 &&
838 (temp & 0x01) == 1) {
839 scsi_add_device(acb->host,
840 0, target, lun);
841 } else if ((diff & 0x01) == 1
842 && (temp & 0x01) == 0) {
843 psdev = scsi_device_lookup(acb->host,
844 0, target, lun);
845 if (psdev != NULL) {
846 scsi_remove_device(psdev);
847 scsi_device_put(psdev);
Nick Cheng36b83de2010-05-17 11:22:42 +0800848 }
Nick Cheng36b83de2010-05-17 11:22:42 +0800849 }
Ching Huang12aad942014-08-19 14:59:00 +0800850 temp >>= 1;
851 diff >>= 1;
Nick Cheng36b83de2010-05-17 11:22:42 +0800852 }
853 }
Ching Huang12aad942014-08-19 14:59:00 +0800854 devicemap++;
855 acb_dev_map++;
Nick Cheng36b83de2010-05-17 11:22:42 +0800856 }
857}
Erich Chen1c57e862006-07-12 08:59:32 -0700858
Ching Huang1d1166e2014-08-19 14:23:31 +0800859static int
860arcmsr_request_irq(struct pci_dev *pdev, struct AdapterControlBlock *acb)
861{
Christoph Hellwig68130c92016-09-11 15:31:23 +0200862 unsigned long flags;
863 int nvec, i;
Ching Huang1d1166e2014-08-19 14:23:31 +0800864
Ching Huang07640402017-12-05 10:26:38 +0800865 if (msix_enable == 0)
866 goto msi_int0;
Christoph Hellwig68130c92016-09-11 15:31:23 +0200867 nvec = pci_alloc_irq_vectors(pdev, 1, ARCMST_NUM_MSIX_VECTORS,
868 PCI_IRQ_MSIX);
869 if (nvec > 0) {
870 pr_info("arcmsr%d: msi-x enabled\n", acb->host->host_no);
871 flags = 0;
872 } else {
Ching Huang07640402017-12-05 10:26:38 +0800873msi_int0:
Ching Huanga18686e2017-12-05 10:24:01 +0800874 if (msi_enable == 1) {
875 nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
876 if (nvec == 1) {
877 dev_info(&pdev->dev, "msi enabled\n");
878 goto msi_int1;
879 }
880 }
881 nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
Christoph Hellwig68130c92016-09-11 15:31:23 +0200882 if (nvec < 1)
883 return FAILED;
Ching Huanga18686e2017-12-05 10:24:01 +0800884msi_int1:
Christoph Hellwig68130c92016-09-11 15:31:23 +0200885 flags = IRQF_SHARED;
886 }
887
888 acb->vector_count = nvec;
889 for (i = 0; i < nvec; i++) {
890 if (request_irq(pci_irq_vector(pdev, i), arcmsr_do_interrupt,
891 flags, "arcmsr", acb)) {
Ching Huang1d1166e2014-08-19 14:23:31 +0800892 pr_warn("arcmsr%d: request_irq =%d failed!\n",
Christoph Hellwig68130c92016-09-11 15:31:23 +0200893 acb->host->host_no, pci_irq_vector(pdev, i));
894 goto out_free_irq;
Ching Huang1d1166e2014-08-19 14:23:31 +0800895 }
Ching Huang1d1166e2014-08-19 14:23:31 +0800896 }
Christoph Hellwig68130c92016-09-11 15:31:23 +0200897
Ching Huang1d1166e2014-08-19 14:23:31 +0800898 return SUCCESS;
Christoph Hellwig68130c92016-09-11 15:31:23 +0200899out_free_irq:
900 while (--i >= 0)
901 free_irq(pci_irq_vector(pdev, i), acb);
902 pci_free_irq_vectors(pdev);
903 return FAILED;
Ching Huang1d1166e2014-08-19 14:23:31 +0800904}
905
Ching Huangea331f32017-12-05 10:11:23 +0800906static void arcmsr_init_get_devmap_timer(struct AdapterControlBlock *pacb)
907{
908 INIT_WORK(&pacb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
909 atomic_set(&pacb->rq_map_token, 16);
910 atomic_set(&pacb->ante_token_value, 16);
911 pacb->fw_flag = FW_NORMAL;
912 timer_setup(&pacb->eternal_timer, arcmsr_request_device_map, 0);
913 pacb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
914 add_timer(&pacb->eternal_timer);
915}
916
Ching Huangb416c092017-12-05 09:59:52 +0800917static void arcmsr_init_set_datetime_timer(struct AdapterControlBlock *pacb)
918{
919 timer_setup(&pacb->refresh_timer, arcmsr_set_iop_datetime, 0);
920 pacb->refresh_timer.expires = jiffies + msecs_to_jiffies(60 * 1000);
921 add_timer(&pacb->refresh_timer);
922}
923
Ching Huang1d120c62018-12-19 16:56:34 +0800924static int arcmsr_set_dma_mask(struct AdapterControlBlock *acb)
925{
926 struct pci_dev *pcidev = acb->pdev;
927
928 if (IS_DMA64) {
929 if (((acb->adapter_type == ACB_ADAPTER_TYPE_A) && !dma_mask_64) ||
930 dma_set_mask(&pcidev->dev, DMA_BIT_MASK(64)))
931 goto dma32;
932 if (dma_set_coherent_mask(&pcidev->dev, DMA_BIT_MASK(64)) ||
933 dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64))) {
934 printk("arcmsr: set DMA 64 mask failed\n");
935 return -ENXIO;
936 }
937 } else {
938dma32:
939 if (dma_set_mask(&pcidev->dev, DMA_BIT_MASK(32)) ||
940 dma_set_coherent_mask(&pcidev->dev, DMA_BIT_MASK(32)) ||
941 dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32))) {
942 printk("arcmsr: set DMA 32-bit mask failed\n");
943 return -ENXIO;
944 }
945 }
946 return 0;
947}
948
Nick Chengae52e7f2010-06-18 15:39:12 +0800949static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Erich Chen1c57e862006-07-12 08:59:32 -0700950{
951 struct Scsi_Host *host;
952 struct AdapterControlBlock *acb;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800953 uint8_t bus,dev_fun;
Erich Chen1c57e862006-07-12 08:59:32 -0700954 int error;
Erich Chen1c57e862006-07-12 08:59:32 -0700955 error = pci_enable_device(pdev);
Nick Chengcdd3cb12010-07-13 20:03:04 +0800956 if(error){
Nick Chengae52e7f2010-06-18 15:39:12 +0800957 return -ENODEV;
Erich Chen1c57e862006-07-12 08:59:32 -0700958 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800959 host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
Nick Chengcdd3cb12010-07-13 20:03:04 +0800960 if(!host){
961 goto pci_disable_dev;
Nick Chengae52e7f2010-06-18 15:39:12 +0800962 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800963 init_waitqueue_head(&wait_q);
Erich Chen1c57e862006-07-12 08:59:32 -0700964 bus = pdev->bus->number;
965 dev_fun = pdev->devfn;
Nick Chengae52e7f2010-06-18 15:39:12 +0800966 acb = (struct AdapterControlBlock *) host->hostdata;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800967 memset(acb,0,sizeof(struct AdapterControlBlock));
Erich Chen1c57e862006-07-12 08:59:32 -0700968 acb->pdev = pdev;
Ching Huang1d120c62018-12-19 16:56:34 +0800969 acb->adapter_type = id->driver_data;
970 if (arcmsr_set_dma_mask(acb))
971 goto scsi_host_release;
Nick Chengae52e7f2010-06-18 15:39:12 +0800972 acb->host = host;
Erich Chen1c57e862006-07-12 08:59:32 -0700973 host->max_lun = ARCMSR_MAX_TARGETLUN;
Nick Chengcdd3cb12010-07-13 20:03:04 +0800974 host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/
975 host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/
Ching Huangdd6206e2017-12-05 09:47:44 +0800976 if ((host_can_queue < ARCMSR_MIN_OUTSTANDING_CMD) || (host_can_queue > ARCMSR_MAX_OUTSTANDING_CMD))
977 host_can_queue = ARCMSR_DEFAULT_OUTSTANDING_CMD;
978 host->can_queue = host_can_queue; /* max simultaneous cmds */
Ching Huangabf33d82017-12-05 09:55:02 +0800979 if ((cmd_per_lun < ARCMSR_MIN_CMD_PERLUN) || (cmd_per_lun > ARCMSR_MAX_CMD_PERLUN))
980 cmd_per_lun = ARCMSR_DEFAULT_CMD_PERLUN;
981 host->cmd_per_lun = cmd_per_lun;
Erich Chen1c57e862006-07-12 08:59:32 -0700982 host->this_id = ARCMSR_SCSI_INITIATOR_ID;
983 host->unique_id = (bus << 8) | dev_fun;
Nick Chengae52e7f2010-06-18 15:39:12 +0800984 pci_set_drvdata(pdev, host);
985 pci_set_master(pdev);
Erich Chen1c57e862006-07-12 08:59:32 -0700986 error = pci_request_regions(pdev, "arcmsr");
Nick Chengcdd3cb12010-07-13 20:03:04 +0800987 if(error){
Nick Chengae52e7f2010-06-18 15:39:12 +0800988 goto scsi_host_release;
Erich Chen1c57e862006-07-12 08:59:32 -0700989 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800990 spin_lock_init(&acb->eh_lock);
991 spin_lock_init(&acb->ccblist_lock);
Ching Huang5b374792014-08-19 15:25:22 +0800992 spin_lock_init(&acb->postq_lock);
993 spin_lock_init(&acb->doneq_lock);
Ching Huangbb263c42014-08-19 15:17:45 +0800994 spin_lock_init(&acb->rqbuffer_lock);
995 spin_lock_init(&acb->wqbuffer_lock);
Erich Chen1c57e862006-07-12 08:59:32 -0700996 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
Nick Chengcdd3cb12010-07-13 20:03:04 +0800997 ACB_F_MESSAGE_RQBUFFER_CLEARED |
998 ACB_F_MESSAGE_WQBUFFER_READED);
Erich Chen1c57e862006-07-12 08:59:32 -0700999 acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
1000 INIT_LIST_HEAD(&acb->ccb_free_list);
Nick Chengae52e7f2010-06-18 15:39:12 +08001001 error = arcmsr_remap_pciregion(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001002 if(!error){
Nick Chengae52e7f2010-06-18 15:39:12 +08001003 goto pci_release_regs;
1004 }
Ching Huang02040672015-11-26 19:41:15 +08001005 error = arcmsr_alloc_io_queue(acb);
1006 if (!error)
1007 goto unmap_pci_region;
Nick Chengae52e7f2010-06-18 15:39:12 +08001008 error = arcmsr_get_firmware_spec(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001009 if(!error){
Ching Huang02040672015-11-26 19:41:15 +08001010 goto free_hbb_mu;
Nick Chengae52e7f2010-06-18 15:39:12 +08001011 }
Ching Huang222f1182018-12-19 16:31:00 +08001012 arcmsr_free_io_queue(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001013 error = arcmsr_alloc_ccb_pool(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001014 if(error){
Ching Huang222f1182018-12-19 16:31:00 +08001015 goto unmap_pci_region;
Nick Chengae52e7f2010-06-18 15:39:12 +08001016 }
Erich Chen1c57e862006-07-12 08:59:32 -07001017 error = scsi_add_host(host, &pdev->dev);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001018 if(error){
Ching Huangb4eb6ae2014-08-19 15:28:36 +08001019 goto free_ccb_pool;
Nick Chengae52e7f2010-06-18 15:39:12 +08001020 }
Ching Huang1d1166e2014-08-19 14:23:31 +08001021 if (arcmsr_request_irq(pdev, acb) == FAILED)
Nick Chengae52e7f2010-06-18 15:39:12 +08001022 goto scsi_host_remove;
Ching Huang1d1166e2014-08-19 14:23:31 +08001023 arcmsr_iop_init(acb);
Ching Huangea331f32017-12-05 10:11:23 +08001024 arcmsr_init_get_devmap_timer(acb);
Ching Huangb416c092017-12-05 09:59:52 +08001025 if (set_date_time)
1026 arcmsr_init_set_datetime_timer(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001027 if(arcmsr_alloc_sysfs_attr(acb))
Nick Chengae52e7f2010-06-18 15:39:12 +08001028 goto out_free_sysfs;
Ching Huangb4eb6ae2014-08-19 15:28:36 +08001029 scsi_scan_host(host);
Erich Chen1c57e862006-07-12 08:59:32 -07001030 return 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001031out_free_sysfs:
Ching Huangb416c092017-12-05 09:59:52 +08001032 if (set_date_time)
1033 del_timer_sync(&acb->refresh_timer);
Ching Huangb4eb6ae2014-08-19 15:28:36 +08001034 del_timer_sync(&acb->eternal_timer);
1035 flush_work(&acb->arcmsr_do_message_isr_bh);
Nick Chengae52e7f2010-06-18 15:39:12 +08001036 arcmsr_stop_adapter_bgrb(acb);
1037 arcmsr_flush_adapter_cache(acb);
Ching Huangb4eb6ae2014-08-19 15:28:36 +08001038 arcmsr_free_irq(pdev, acb);
1039scsi_host_remove:
1040 scsi_remove_host(host);
1041free_ccb_pool:
Erich Chen1c57e862006-07-12 08:59:32 -07001042 arcmsr_free_ccb_pool(acb);
Ching Huang222f1182018-12-19 16:31:00 +08001043 goto unmap_pci_region;
Nick Chengae52e7f2010-06-18 15:39:12 +08001044free_hbb_mu:
Ching Huang609d0852018-12-19 16:27:20 +08001045 arcmsr_free_io_queue(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +08001046unmap_pci_region:
1047 arcmsr_unmap_pciregion(acb);
1048pci_release_regs:
Erich Chen1c57e862006-07-12 08:59:32 -07001049 pci_release_regions(pdev);
Nick Chengae52e7f2010-06-18 15:39:12 +08001050scsi_host_release:
Erich Chen1c57e862006-07-12 08:59:32 -07001051 scsi_host_put(host);
Nick Chengae52e7f2010-06-18 15:39:12 +08001052pci_disable_dev:
Erich Chen1c57e862006-07-12 08:59:32 -07001053 pci_disable_device(pdev);
Nick Chengae52e7f2010-06-18 15:39:12 +08001054 return -ENODEV;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001055}
1056
Ching Huang1d1166e2014-08-19 14:23:31 +08001057static void arcmsr_free_irq(struct pci_dev *pdev,
1058 struct AdapterControlBlock *acb)
1059{
1060 int i;
1061
Christoph Hellwig68130c92016-09-11 15:31:23 +02001062 for (i = 0; i < acb->vector_count; i++)
1063 free_irq(pci_irq_vector(pdev, i), acb);
1064 pci_free_irq_vectors(pdev);
Ching Huang1d1166e2014-08-19 14:23:31 +08001065}
1066
Ching Huang61cda872014-08-19 14:26:09 +08001067static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state)
1068{
Ching Huang61cda872014-08-19 14:26:09 +08001069 struct Scsi_Host *host = pci_get_drvdata(pdev);
1070 struct AdapterControlBlock *acb =
1071 (struct AdapterControlBlock *)host->hostdata;
1072
Lee Jones18bc4352020-07-13 08:46:30 +01001073 arcmsr_disable_outbound_ints(acb);
Ching Huang61cda872014-08-19 14:26:09 +08001074 arcmsr_free_irq(pdev, acb);
1075 del_timer_sync(&acb->eternal_timer);
Ching Huangb416c092017-12-05 09:59:52 +08001076 if (set_date_time)
1077 del_timer_sync(&acb->refresh_timer);
Ching Huang61cda872014-08-19 14:26:09 +08001078 flush_work(&acb->arcmsr_do_message_isr_bh);
1079 arcmsr_stop_adapter_bgrb(acb);
1080 arcmsr_flush_adapter_cache(acb);
1081 pci_set_drvdata(pdev, host);
1082 pci_save_state(pdev);
1083 pci_disable_device(pdev);
1084 pci_set_power_state(pdev, pci_choose_state(pdev, state));
1085 return 0;
1086}
1087
1088static int arcmsr_resume(struct pci_dev *pdev)
1089{
Ching Huang61cda872014-08-19 14:26:09 +08001090 struct Scsi_Host *host = pci_get_drvdata(pdev);
1091 struct AdapterControlBlock *acb =
1092 (struct AdapterControlBlock *)host->hostdata;
1093
1094 pci_set_power_state(pdev, PCI_D0);
1095 pci_enable_wake(pdev, PCI_D0, 0);
1096 pci_restore_state(pdev);
1097 if (pci_enable_device(pdev)) {
1098 pr_warn("%s: pci_enable_device error\n", __func__);
1099 return -ENODEV;
1100 }
Ching Huang1d120c62018-12-19 16:56:34 +08001101 if (arcmsr_set_dma_mask(acb))
1102 goto controller_unregister;
Ching Huang61cda872014-08-19 14:26:09 +08001103 pci_set_master(pdev);
1104 if (arcmsr_request_irq(pdev, acb) == FAILED)
1105 goto controller_stop;
Ching Huangafdda872018-12-19 16:59:48 +08001106 switch (acb->adapter_type) {
1107 case ACB_ADAPTER_TYPE_B: {
1108 struct MessageUnit_B *reg = acb->pmuB;
Ching Huang317d0e02019-01-18 10:58:51 +08001109 uint32_t i;
1110 for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
1111 reg->post_qbuffer[i] = 0;
1112 reg->done_qbuffer[i] = 0;
1113 }
Ching Huangafdda872018-12-19 16:59:48 +08001114 reg->postq_index = 0;
1115 reg->doneq_index = 0;
1116 break;
1117 }
1118 case ACB_ADAPTER_TYPE_E:
Ching Huang97fe2222018-07-09 18:24:53 +08001119 writel(0, &acb->pmuE->host_int_status);
1120 writel(ARCMSR_HBEMU_DOORBELL_SYNC, &acb->pmuE->iobound_doorbell);
1121 acb->in_doorbell = 0;
1122 acb->out_doorbell = 0;
1123 acb->doneq_index = 0;
Ching Huangafdda872018-12-19 16:59:48 +08001124 break;
Ching Huang97fe2222018-07-09 18:24:53 +08001125 }
Ching Huang61cda872014-08-19 14:26:09 +08001126 arcmsr_iop_init(acb);
Ching Huangea331f32017-12-05 10:11:23 +08001127 arcmsr_init_get_devmap_timer(acb);
Ching Huangb416c092017-12-05 09:59:52 +08001128 if (set_date_time)
1129 arcmsr_init_set_datetime_timer(acb);
Ching Huang61cda872014-08-19 14:26:09 +08001130 return 0;
1131controller_stop:
1132 arcmsr_stop_adapter_bgrb(acb);
1133 arcmsr_flush_adapter_cache(acb);
1134controller_unregister:
1135 scsi_remove_host(host);
1136 arcmsr_free_ccb_pool(acb);
1137 arcmsr_unmap_pciregion(acb);
1138 pci_release_regions(pdev);
1139 scsi_host_put(host);
1140 pci_disable_device(pdev);
1141 return -ENODEV;
1142}
1143
Ching Huang626fa322014-08-19 15:10:12 +08001144static uint8_t arcmsr_hbaA_abort_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001145{
Al Viro80da1ad2007-10-29 05:08:28 +00001146 struct MessageUnit_A __iomem *reg = acb->pmuA;
Erich Chen1c57e862006-07-12 08:59:32 -07001147 writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
Ching Huang626fa322014-08-19 15:10:12 +08001148 if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
Erich Chen1c57e862006-07-12 08:59:32 -07001149 printk(KERN_NOTICE
Ching Huang626fa322014-08-19 15:10:12 +08001150 "arcmsr%d: wait 'abort all outstanding command' timeout\n"
Erich Chen1c57e862006-07-12 08:59:32 -07001151 , acb->host->host_no);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001152 return false;
Nick Cheng36b83de2010-05-17 11:22:42 +08001153 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001154 return true;
Erich Chen1c57e862006-07-12 08:59:32 -07001155}
1156
Ching Huang626fa322014-08-19 15:10:12 +08001157static uint8_t arcmsr_hbaB_abort_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001158{
Al Viro80da1ad2007-10-29 05:08:28 +00001159 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001160
Nick Chengae52e7f2010-06-18 15:39:12 +08001161 writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08001162 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001163 printk(KERN_NOTICE
Ching Huang626fa322014-08-19 15:10:12 +08001164 "arcmsr%d: wait 'abort all outstanding command' timeout\n"
Nick Cheng1a4f5502007-09-13 17:26:40 +08001165 , acb->host->host_no);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001166 return false;
Nick Cheng36b83de2010-05-17 11:22:42 +08001167 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001168 return true;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001169}
Ching Huang626fa322014-08-19 15:10:12 +08001170static uint8_t arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08001171{
Ching Huangc10b1d52014-08-19 15:20:31 +08001172 struct MessageUnit_C __iomem *reg = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001173 writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
1174 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08001175 if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08001176 printk(KERN_NOTICE
Ching Huang626fa322014-08-19 15:10:12 +08001177 "arcmsr%d: wait 'abort all outstanding command' timeout\n"
Nick Chengcdd3cb12010-07-13 20:03:04 +08001178 , pACB->host->host_no);
1179 return false;
1180 }
1181 return true;
1182}
Ching Huang5b374792014-08-19 15:25:22 +08001183
1184static uint8_t arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
1185{
1186 struct MessageUnit_D *reg = pACB->pmuD;
1187
1188 writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, reg->inbound_msgaddr0);
1189 if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
1190 pr_notice("arcmsr%d: wait 'abort all outstanding "
1191 "command' timeout\n", pACB->host->host_no);
1192 return false;
1193 }
1194 return true;
1195}
1196
Ching Huang23509022017-12-05 09:35:34 +08001197static uint8_t arcmsr_hbaE_abort_allcmd(struct AdapterControlBlock *pACB)
1198{
1199 struct MessageUnit_E __iomem *reg = pACB->pmuE;
1200
1201 writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
1202 pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
1203 writel(pACB->out_doorbell, &reg->iobound_doorbell);
1204 if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
1205 pr_notice("arcmsr%d: wait 'abort all outstanding "
1206 "command' timeout\n", pACB->host->host_no);
1207 return false;
1208 }
1209 return true;
1210}
1211
Nick Cheng36b83de2010-05-17 11:22:42 +08001212static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001213{
Nick Cheng36b83de2010-05-17 11:22:42 +08001214 uint8_t rtnval = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001215 switch (acb->adapter_type) {
1216 case ACB_ADAPTER_TYPE_A: {
Ching Huang626fa322014-08-19 15:10:12 +08001217 rtnval = arcmsr_hbaA_abort_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001218 }
1219 break;
1220
1221 case ACB_ADAPTER_TYPE_B: {
Ching Huang626fa322014-08-19 15:10:12 +08001222 rtnval = arcmsr_hbaB_abort_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001223 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001224 break;
1225
1226 case ACB_ADAPTER_TYPE_C: {
Ching Huang626fa322014-08-19 15:10:12 +08001227 rtnval = arcmsr_hbaC_abort_allcmd(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001228 }
Ching Huang5b374792014-08-19 15:25:22 +08001229 break;
1230
1231 case ACB_ADAPTER_TYPE_D:
1232 rtnval = arcmsr_hbaD_abort_allcmd(acb);
1233 break;
Ching Huang23509022017-12-05 09:35:34 +08001234 case ACB_ADAPTER_TYPE_E:
1235 rtnval = arcmsr_hbaE_abort_allcmd(acb);
1236 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001237 }
Nick Cheng36b83de2010-05-17 11:22:42 +08001238 return rtnval;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001239}
1240
Erich Chen1c57e862006-07-12 08:59:32 -07001241static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
1242{
Erich Chen1c57e862006-07-12 08:59:32 -07001243 struct scsi_cmnd *pcmd = ccb->pcmd;
1244
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001245 scsi_dma_unmap(pcmd);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001246}
Erich Chen1c57e862006-07-12 08:59:32 -07001247
Nick Chengae52e7f2010-06-18 15:39:12 +08001248static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
Erich Chen1c57e862006-07-12 08:59:32 -07001249{
1250 struct AdapterControlBlock *acb = ccb->acb;
1251 struct scsi_cmnd *pcmd = ccb->pcmd;
Nick Chengae52e7f2010-06-18 15:39:12 +08001252 unsigned long flags;
Nick Chengae52e7f2010-06-18 15:39:12 +08001253 atomic_dec(&acb->ccboutstandingcount);
Erich Chen1c57e862006-07-12 08:59:32 -07001254 arcmsr_pci_unmap_dma(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07001255 ccb->startdone = ARCMSR_CCB_DONE;
Nick Chengae52e7f2010-06-18 15:39:12 +08001256 spin_lock_irqsave(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07001257 list_add_tail(&ccb->list, &acb->ccb_free_list);
Nick Chengae52e7f2010-06-18 15:39:12 +08001258 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07001259 pcmd->scsi_done(pcmd);
1260}
1261
Nick Cheng1a4f5502007-09-13 17:26:40 +08001262static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
1263{
1264
1265 struct scsi_cmnd *pcmd = ccb->pcmd;
1266 struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
Ching Huangfa576b42017-12-05 11:28:37 +08001267 pcmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001268 if (sensebuffer) {
1269 int sense_data_length =
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +09001270 sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
1271 ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
1272 memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001273 memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
1274 sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
1275 sensebuffer->Valid = 1;
Ching Huangfa576b42017-12-05 11:28:37 +08001276 pcmd->result |= (DRIVER_SENSE << 24);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001277 }
1278}
1279
1280static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
1281{
1282 u32 orig_mask = 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001283 switch (acb->adapter_type) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001284 case ACB_ADAPTER_TYPE_A : {
Al Viro80da1ad2007-10-29 05:08:28 +00001285 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +08001286 orig_mask = readl(&reg->outbound_intmask);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001287 writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
1288 &reg->outbound_intmask);
1289 }
1290 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001291 case ACB_ADAPTER_TYPE_B : {
Al Viro80da1ad2007-10-29 05:08:28 +00001292 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001293 orig_mask = readl(reg->iop2drv_doorbell_mask);
1294 writel(0, reg->iop2drv_doorbell_mask);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001295 }
1296 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001297 case ACB_ADAPTER_TYPE_C:{
Ching Huangc10b1d52014-08-19 15:20:31 +08001298 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001299 /* disable all outbound interrupt */
1300 orig_mask = readl(&reg->host_int_mask); /* disable outbound message0 int */
1301 writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
1302 }
1303 break;
Ching Huang5b374792014-08-19 15:25:22 +08001304 case ACB_ADAPTER_TYPE_D: {
1305 struct MessageUnit_D *reg = acb->pmuD;
1306 /* disable all outbound interrupt */
1307 writel(ARCMSR_ARC1214_ALL_INT_DISABLE, reg->pcief0_int_enable);
1308 }
1309 break;
Ching Huang23509022017-12-05 09:35:34 +08001310 case ACB_ADAPTER_TYPE_E: {
1311 struct MessageUnit_E __iomem *reg = acb->pmuE;
1312 orig_mask = readl(&reg->host_int_mask);
1313 writel(orig_mask | ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR | ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR, &reg->host_int_mask);
1314 readl(&reg->host_int_mask); /* Dummy readl to force pci flush */
1315 }
1316 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001317 }
1318 return orig_mask;
1319}
1320
Nick Chengcdd3cb12010-07-13 20:03:04 +08001321static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
1322 struct CommandControlBlock *ccb, bool error)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001323{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001324 uint8_t id, lun;
1325 id = ccb->pcmd->device->id;
1326 lun = ccb->pcmd->device->lun;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001327 if (!error) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001328 if (acb->devstate[id][lun] == ARECA_RAID_GONE)
1329 acb->devstate[id][lun] = ARECA_RAID_GOOD;
Julia Lawall7968f192010-08-05 22:19:36 +02001330 ccb->pcmd->result = DID_OK << 16;
1331 arcmsr_ccb_complete(ccb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001332 }else{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001333 switch (ccb->arcmsr_cdb.DeviceStatus) {
1334 case ARCMSR_DEV_SELECT_TIMEOUT: {
1335 acb->devstate[id][lun] = ARECA_RAID_GONE;
1336 ccb->pcmd->result = DID_NO_CONNECT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08001337 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001338 }
1339 break;
1340
1341 case ARCMSR_DEV_ABORTED:
1342
1343 case ARCMSR_DEV_INIT_FAIL: {
1344 acb->devstate[id][lun] = ARECA_RAID_GONE;
1345 ccb->pcmd->result = DID_BAD_TARGET << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08001346 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001347 }
1348 break;
1349
1350 case ARCMSR_DEV_CHECK_CONDITION: {
1351 acb->devstate[id][lun] = ARECA_RAID_GOOD;
1352 arcmsr_report_sense_info(ccb);
Nick Chengae52e7f2010-06-18 15:39:12 +08001353 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001354 }
1355 break;
1356
1357 default:
Nick Chengcdd3cb12010-07-13 20:03:04 +08001358 printk(KERN_NOTICE
1359 "arcmsr%d: scsi id = %d lun = %d isr get command error done, \
1360 but got unknown DeviceStatus = 0x%x \n"
1361 , acb->host->host_no
1362 , id
1363 , lun
1364 , ccb->arcmsr_cdb.DeviceStatus);
1365 acb->devstate[id][lun] = ARECA_RAID_GONE;
1366 ccb->pcmd->result = DID_NO_CONNECT << 16;
1367 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001368 break;
1369 }
1370 }
1371}
1372
Nick Chengcdd3cb12010-07-13 20:03:04 +08001373static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001374{
Nick Chengcdd3cb12010-07-13 20:03:04 +08001375 if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
1376 if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
1377 struct scsi_cmnd *abortcmd = pCCB->pcmd;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001378 if (abortcmd) {
1379 abortcmd->result |= DID_ABORT << 16;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001380 arcmsr_ccb_complete(pCCB);
1381 printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
1382 acb->host->host_no, pCCB);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001383 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001384 return;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001385 }
1386 printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
1387 done acb = '0x%p'"
1388 "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
1389 " ccboutstandingcount = %d \n"
1390 , acb->host->host_no
1391 , acb
Nick Chengcdd3cb12010-07-13 20:03:04 +08001392 , pCCB
1393 , pCCB->acb
1394 , pCCB->startdone
Nick Cheng1a4f5502007-09-13 17:26:40 +08001395 , atomic_read(&acb->ccboutstandingcount));
Colin Ian King9b44ffa2019-11-14 18:00:07 +00001396 return;
NickCheng97b99122011-01-06 17:32:41 +08001397 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001398 arcmsr_report_ccb_state(acb, pCCB, error);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001399}
1400
1401static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
1402{
1403 int i = 0;
Ching Huang9e386a52018-12-19 16:43:15 +08001404 uint32_t flag_ccb;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001405 struct ARCMSR_CDB *pARCMSR_CDB;
1406 bool error;
1407 struct CommandControlBlock *pCCB;
Lee Jones18bc4352020-07-13 08:46:30 +01001408 unsigned long ccb_cdb_phy;
Ching Huang9e386a52018-12-19 16:43:15 +08001409
Nick Cheng1a4f5502007-09-13 17:26:40 +08001410 switch (acb->adapter_type) {
1411
1412 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001413 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001414 uint32_t outbound_intstatus;
Al Viro80da1ad2007-10-29 05:08:28 +00001415 outbound_intstatus = readl(&reg->outbound_intstatus) &
Nick Cheng1a4f5502007-09-13 17:26:40 +08001416 acb->outbound_int_enable;
1417 /*clear and abort all outbound posted Q*/
1418 writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
Nick Chengcdd3cb12010-07-13 20:03:04 +08001419 while(((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
Ching Huange4587f42017-12-05 09:51:27 +08001420 && (i++ < acb->maxOutstanding)) {
Ching Huang9e386a52018-12-19 16:43:15 +08001421 ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
1422 if (acb->cdb_phyadd_hipart)
1423 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
1424 pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001425 pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
1426 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
1427 arcmsr_drain_donequeue(acb, pCCB, error);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001428 }
1429 }
1430 break;
1431
1432 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001433 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001434 /*clear all outbound posted Q*/
NickCheng97b99122011-01-06 17:32:41 +08001435 writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */
Nick Cheng1a4f5502007-09-13 17:26:40 +08001436 for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
Ching Huangc10b1d52014-08-19 15:20:31 +08001437 flag_ccb = reg->done_qbuffer[i];
1438 if (flag_ccb != 0) {
1439 reg->done_qbuffer[i] = 0;
Ching Huange66764f2018-12-19 16:45:46 +08001440 ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
1441 if (acb->cdb_phyadd_hipart)
1442 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
1443 pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001444 pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
1445 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
1446 arcmsr_drain_donequeue(acb, pCCB, error);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001447 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001448 reg->post_qbuffer[i] = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001449 }
1450 reg->doneq_index = 0;
1451 reg->postq_index = 0;
1452 }
1453 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001454 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08001455 struct MessageUnit_C __iomem *reg = acb->pmuC;
Ching Huange4587f42017-12-05 09:51:27 +08001456 while ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < acb->maxOutstanding)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08001457 /*need to do*/
1458 flag_ccb = readl(&reg->outbound_queueport_low);
1459 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
Ching Huangc71ec552018-12-19 16:48:16 +08001460 if (acb->cdb_phyadd_hipart)
1461 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
1462 pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001463 pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
1464 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
1465 arcmsr_drain_donequeue(acb, pCCB, error);
1466 }
Ching Huang5b374792014-08-19 15:25:22 +08001467 }
1468 break;
1469 case ACB_ADAPTER_TYPE_D: {
1470 struct MessageUnit_D *pmu = acb->pmuD;
Ching Huang3b8155d2014-09-15 19:05:33 +08001471 uint32_t outbound_write_pointer;
1472 uint32_t doneq_index, index_stripped, addressLow, residual, toggle;
1473 unsigned long flags;
Ching Huang5b374792014-08-19 15:25:22 +08001474
Ching Huang5b374792014-08-19 15:25:22 +08001475 residual = atomic_read(&acb->ccboutstandingcount);
1476 for (i = 0; i < residual; i++) {
Ching Huang3b8155d2014-09-15 19:05:33 +08001477 spin_lock_irqsave(&acb->doneq_lock, flags);
1478 outbound_write_pointer =
1479 pmu->done_qbuffer[0].addressLow + 1;
1480 doneq_index = pmu->doneq_index;
1481 if ((doneq_index & 0xFFF) !=
Ching Huang5b374792014-08-19 15:25:22 +08001482 (outbound_write_pointer & 0xFFF)) {
Ching Huang3b8155d2014-09-15 19:05:33 +08001483 toggle = doneq_index & 0x4000;
1484 index_stripped = (doneq_index & 0xFFF) + 1;
1485 index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
1486 pmu->doneq_index = index_stripped ? (index_stripped | toggle) :
1487 ((toggle ^ 0x4000) + 1);
Ching Huang5b374792014-08-19 15:25:22 +08001488 doneq_index = pmu->doneq_index;
Ching Huang3b8155d2014-09-15 19:05:33 +08001489 spin_unlock_irqrestore(&acb->doneq_lock, flags);
Ching Huang5b374792014-08-19 15:25:22 +08001490 addressLow = pmu->done_qbuffer[doneq_index &
1491 0xFFF].addressLow;
1492 ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
Ching Huanga36ade42018-12-19 16:51:14 +08001493 if (acb->cdb_phyadd_hipart)
1494 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
Ching Huang5b374792014-08-19 15:25:22 +08001495 pARCMSR_CDB = (struct ARCMSR_CDB *)
1496 (acb->vir2phy_offset + ccb_cdb_phy);
1497 pCCB = container_of(pARCMSR_CDB,
1498 struct CommandControlBlock, arcmsr_cdb);
1499 error = (addressLow &
1500 ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ?
1501 true : false;
1502 arcmsr_drain_donequeue(acb, pCCB, error);
1503 writel(doneq_index,
1504 pmu->outboundlist_read_pointer);
Ching Huang3b8155d2014-09-15 19:05:33 +08001505 } else {
1506 spin_unlock_irqrestore(&acb->doneq_lock, flags);
1507 mdelay(10);
Ching Huang5b374792014-08-19 15:25:22 +08001508 }
Ching Huang5b374792014-08-19 15:25:22 +08001509 }
1510 pmu->postq_index = 0;
1511 pmu->doneq_index = 0x40FF;
1512 }
1513 break;
Ching Huang23509022017-12-05 09:35:34 +08001514 case ACB_ADAPTER_TYPE_E:
1515 arcmsr_hbaE_postqueue_isr(acb);
1516 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001517 }
1518}
Ching Huang1d1166e2014-08-19 14:23:31 +08001519
Ching Huangc4c1adb2018-03-15 14:33:36 +08001520static void arcmsr_remove_scsi_devices(struct AdapterControlBlock *acb)
1521{
1522 char *acb_dev_map = (char *)acb->device_map;
1523 int target, lun, i;
1524 struct scsi_device *psdev;
1525 struct CommandControlBlock *ccb;
1526 char temp;
1527
1528 for (i = 0; i < acb->maxFreeCCB; i++) {
1529 ccb = acb->pccb_pool[i];
1530 if (ccb->startdone == ARCMSR_CCB_START) {
1531 ccb->pcmd->result = DID_NO_CONNECT << 16;
1532 arcmsr_pci_unmap_dma(ccb);
1533 ccb->pcmd->scsi_done(ccb->pcmd);
1534 }
1535 }
1536 for (target = 0; target < ARCMSR_MAX_TARGETID; target++) {
1537 temp = *acb_dev_map;
1538 if (temp) {
1539 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
1540 if (temp & 1) {
1541 psdev = scsi_device_lookup(acb->host,
1542 0, target, lun);
1543 if (psdev != NULL) {
1544 scsi_remove_device(psdev);
1545 scsi_device_put(psdev);
1546 }
1547 }
1548 temp >>= 1;
1549 }
1550 *acb_dev_map = 0;
1551 }
1552 acb_dev_map++;
1553 }
1554}
1555
1556static void arcmsr_free_pcidev(struct AdapterControlBlock *acb)
1557{
1558 struct pci_dev *pdev;
1559 struct Scsi_Host *host;
1560
1561 host = acb->host;
1562 arcmsr_free_sysfs_attr(acb);
1563 scsi_remove_host(host);
1564 flush_work(&acb->arcmsr_do_message_isr_bh);
1565 del_timer_sync(&acb->eternal_timer);
1566 if (set_date_time)
1567 del_timer_sync(&acb->refresh_timer);
1568 pdev = acb->pdev;
1569 arcmsr_free_irq(pdev, acb);
1570 arcmsr_free_ccb_pool(acb);
Ching Huangc4c1adb2018-03-15 14:33:36 +08001571 arcmsr_unmap_pciregion(acb);
1572 pci_release_regions(pdev);
1573 scsi_host_put(host);
1574 pci_disable_device(pdev);
1575}
1576
Erich Chen1c57e862006-07-12 08:59:32 -07001577static void arcmsr_remove(struct pci_dev *pdev)
1578{
1579 struct Scsi_Host *host = pci_get_drvdata(pdev);
1580 struct AdapterControlBlock *acb =
1581 (struct AdapterControlBlock *) host->hostdata;
Erich Chen1c57e862006-07-12 08:59:32 -07001582 int poll_count = 0;
Ching Huangc4c1adb2018-03-15 14:33:36 +08001583 uint16_t dev_id;
1584
1585 pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
1586 if (dev_id == 0xffff) {
1587 acb->acb_flags &= ~ACB_F_IOP_INITED;
1588 acb->acb_flags |= ACB_F_ADAPTER_REMOVED;
1589 arcmsr_remove_scsi_devices(acb);
1590 arcmsr_free_pcidev(acb);
1591 return;
1592 }
Erich Chen1c57e862006-07-12 08:59:32 -07001593 arcmsr_free_sysfs_attr(acb);
1594 scsi_remove_host(host);
Tejun Heo43829732012-08-20 14:51:24 -07001595 flush_work(&acb->arcmsr_do_message_isr_bh);
Nick Cheng36b83de2010-05-17 11:22:42 +08001596 del_timer_sync(&acb->eternal_timer);
Ching Huangb416c092017-12-05 09:59:52 +08001597 if (set_date_time)
1598 del_timer_sync(&acb->refresh_timer);
Nick Cheng36b83de2010-05-17 11:22:42 +08001599 arcmsr_disable_outbound_ints(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001600 arcmsr_stop_adapter_bgrb(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001601 arcmsr_flush_adapter_cache(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001602 acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
1603 acb->acb_flags &= ~ACB_F_IOP_INITED;
1604
Ching Huange4587f42017-12-05 09:51:27 +08001605 for (poll_count = 0; poll_count < acb->maxOutstanding; poll_count++){
Erich Chen1c57e862006-07-12 08:59:32 -07001606 if (!atomic_read(&acb->ccboutstandingcount))
1607 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001608 arcmsr_interrupt(acb);/* FIXME: need spinlock */
Erich Chen1c57e862006-07-12 08:59:32 -07001609 msleep(25);
1610 }
1611
1612 if (atomic_read(&acb->ccboutstandingcount)) {
1613 int i;
1614
1615 arcmsr_abort_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001616 arcmsr_done4abort_postqueue(acb);
Ching Huangd076e4a2017-12-05 09:44:23 +08001617 for (i = 0; i < acb->maxFreeCCB; i++) {
Erich Chen1c57e862006-07-12 08:59:32 -07001618 struct CommandControlBlock *ccb = acb->pccb_pool[i];
1619 if (ccb->startdone == ARCMSR_CCB_START) {
1620 ccb->startdone = ARCMSR_CCB_ABORTED;
1621 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08001622 arcmsr_ccb_complete(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07001623 }
1624 }
1625 }
Ching Huang1d1166e2014-08-19 14:23:31 +08001626 arcmsr_free_irq(pdev, acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001627 arcmsr_free_ccb_pool(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001628 arcmsr_unmap_pciregion(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001629 pci_release_regions(pdev);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001630 scsi_host_put(host);
Erich Chen1c57e862006-07-12 08:59:32 -07001631 pci_disable_device(pdev);
Erich Chen1c57e862006-07-12 08:59:32 -07001632}
1633
1634static void arcmsr_shutdown(struct pci_dev *pdev)
1635{
1636 struct Scsi_Host *host = pci_get_drvdata(pdev);
1637 struct AdapterControlBlock *acb =
1638 (struct AdapterControlBlock *)host->hostdata;
Ching Huangc4c1adb2018-03-15 14:33:36 +08001639 if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
1640 return;
Nick Cheng36b83de2010-05-17 11:22:42 +08001641 del_timer_sync(&acb->eternal_timer);
Ching Huangb416c092017-12-05 09:59:52 +08001642 if (set_date_time)
1643 del_timer_sync(&acb->refresh_timer);
Nick Cheng36b83de2010-05-17 11:22:42 +08001644 arcmsr_disable_outbound_ints(acb);
Ching Huang1d1166e2014-08-19 14:23:31 +08001645 arcmsr_free_irq(pdev, acb);
Tejun Heo43829732012-08-20 14:51:24 -07001646 flush_work(&acb->arcmsr_do_message_isr_bh);
Erich Chen1c57e862006-07-12 08:59:32 -07001647 arcmsr_stop_adapter_bgrb(acb);
1648 arcmsr_flush_adapter_cache(acb);
1649}
1650
1651static int arcmsr_module_init(void)
1652{
1653 int error = 0;
Erich Chen1c57e862006-07-12 08:59:32 -07001654 error = pci_register_driver(&arcmsr_pci_driver);
1655 return error;
1656}
1657
1658static void arcmsr_module_exit(void)
1659{
1660 pci_unregister_driver(&arcmsr_pci_driver);
1661}
1662module_init(arcmsr_module_init);
1663module_exit(arcmsr_module_exit);
1664
Nick Cheng36b83de2010-05-17 11:22:42 +08001665static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08001666 u32 intmask_org)
Erich Chen1c57e862006-07-12 08:59:32 -07001667{
Erich Chen1c57e862006-07-12 08:59:32 -07001668 u32 mask;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001669 switch (acb->adapter_type) {
1670
Nick Chengcdd3cb12010-07-13 20:03:04 +08001671 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001672 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001673 mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
Nick Cheng36b83de2010-05-17 11:22:42 +08001674 ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
1675 ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001676 writel(mask, &reg->outbound_intmask);
1677 acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
1678 }
1679 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001680
Nick Chengcdd3cb12010-07-13 20:03:04 +08001681 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001682 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng36b83de2010-05-17 11:22:42 +08001683 mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
1684 ARCMSR_IOP2DRV_DATA_READ_OK |
1685 ARCMSR_IOP2DRV_CDB_DONE |
1686 ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
Nick Chengae52e7f2010-06-18 15:39:12 +08001687 writel(mask, reg->iop2drv_doorbell_mask);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001688 acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
1689 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001690 break;
1691 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08001692 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001693 mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
1694 writel(intmask_org & mask, &reg->host_int_mask);
1695 acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
1696 }
Ching Huang5b374792014-08-19 15:25:22 +08001697 break;
1698 case ACB_ADAPTER_TYPE_D: {
1699 struct MessageUnit_D *reg = acb->pmuD;
1700
1701 mask = ARCMSR_ARC1214_ALL_INT_ENABLE;
1702 writel(intmask_org | mask, reg->pcief0_int_enable);
1703 break;
1704 }
Ching Huang23509022017-12-05 09:35:34 +08001705 case ACB_ADAPTER_TYPE_E: {
1706 struct MessageUnit_E __iomem *reg = acb->pmuE;
1707
1708 mask = ~(ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR | ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR);
1709 writel(intmask_org & mask, &reg->host_int_mask);
1710 break;
1711 }
Erich Chen1c57e862006-07-12 08:59:32 -07001712 }
1713}
1714
Nick Cheng76d78302008-02-04 23:53:24 -08001715static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07001716 struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
1717{
1718 struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
1719 int8_t *psge = (int8_t *)&arcmsr_cdb->u;
Al Viro80da1ad2007-10-29 05:08:28 +00001720 __le32 address_lo, address_hi;
Erich Chen1c57e862006-07-12 08:59:32 -07001721 int arccdbsize = 0x30;
Nick Chengae52e7f2010-06-18 15:39:12 +08001722 __le32 length = 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001723 int i;
Nick Chengae52e7f2010-06-18 15:39:12 +08001724 struct scatterlist *sg;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001725 int nseg;
Erich Chen1c57e862006-07-12 08:59:32 -07001726 ccb->pcmd = pcmd;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001727 memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
Erich Chen1c57e862006-07-12 08:59:32 -07001728 arcmsr_cdb->TargetID = pcmd->device->id;
1729 arcmsr_cdb->LUN = pcmd->device->lun;
1730 arcmsr_cdb->Function = 1;
Ching Huang626fa322014-08-19 15:10:12 +08001731 arcmsr_cdb->msgContext = 0;
Erich Chen1c57e862006-07-12 08:59:32 -07001732 memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
Erich Chen1c57e862006-07-12 08:59:32 -07001733
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001734 nseg = scsi_dma_map(pcmd);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001735 if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
Nick Cheng76d78302008-02-04 23:53:24 -08001736 return FAILED;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001737 scsi_for_each_sg(pcmd, sg, nseg, i) {
1738 /* Get the physical address of the current data pointer */
1739 length = cpu_to_le32(sg_dma_len(sg));
1740 address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
1741 address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
1742 if (address_hi == 0) {
1743 struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
Erich Chen1c57e862006-07-12 08:59:32 -07001744
Nick Chengcdd3cb12010-07-13 20:03:04 +08001745 pdma_sg->address = address_lo;
1746 pdma_sg->length = length;
1747 psge += sizeof (struct SG32ENTRY);
1748 arccdbsize += sizeof (struct SG32ENTRY);
1749 } else {
1750 struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
Erich Chen1c57e862006-07-12 08:59:32 -07001751
Nick Chengcdd3cb12010-07-13 20:03:04 +08001752 pdma_sg->addresshigh = address_hi;
1753 pdma_sg->address = address_lo;
1754 pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
1755 psge += sizeof (struct SG64ENTRY);
1756 arccdbsize += sizeof (struct SG64ENTRY);
Erich Chen1c57e862006-07-12 08:59:32 -07001757 }
Erich Chen1c57e862006-07-12 08:59:32 -07001758 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08001759 arcmsr_cdb->sgcount = (uint8_t)nseg;
1760 arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
1761 arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
1762 if ( arccdbsize > 256)
1763 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
roel kluinc32e0612011-01-01 19:40:23 +01001764 if (pcmd->sc_data_direction == DMA_TO_DEVICE)
Nick Chengcdd3cb12010-07-13 20:03:04 +08001765 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001766 ccb->arc_cdb_size = arccdbsize;
Nick Cheng76d78302008-02-04 23:53:24 -08001767 return SUCCESS;
Erich Chen1c57e862006-07-12 08:59:32 -07001768}
1769
1770static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
1771{
Ching Huang626fa322014-08-19 15:10:12 +08001772 uint32_t cdb_phyaddr = ccb->cdb_phyaddr;
Erich Chen1c57e862006-07-12 08:59:32 -07001773 struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
Erich Chen1c57e862006-07-12 08:59:32 -07001774 atomic_inc(&acb->ccboutstandingcount);
1775 ccb->startdone = ARCMSR_CCB_START;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001776 switch (acb->adapter_type) {
1777 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001778 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001779
1780 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
Ching Huang626fa322014-08-19 15:10:12 +08001781 writel(cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
Erich Chen1c57e862006-07-12 08:59:32 -07001782 &reg->inbound_queueport);
Ching Huang626fa322014-08-19 15:10:12 +08001783 else
1784 writel(cdb_phyaddr, &reg->inbound_queueport);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001785 break;
Ching Huang626fa322014-08-19 15:10:12 +08001786 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001787
1788 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001789 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001790 uint32_t ending_index, index = reg->postq_index;
1791
1792 ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
Ching Huangc10b1d52014-08-19 15:20:31 +08001793 reg->post_qbuffer[ending_index] = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001794 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
Ching Huangc10b1d52014-08-19 15:20:31 +08001795 reg->post_qbuffer[index] =
1796 cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001797 } else {
Ching Huangc10b1d52014-08-19 15:20:31 +08001798 reg->post_qbuffer[index] = cdb_phyaddr;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001799 }
1800 index++;
1801 index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
1802 reg->postq_index = index;
Nick Chengae52e7f2010-06-18 15:39:12 +08001803 writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001804 }
1805 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001806 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08001807 struct MessageUnit_C __iomem *phbcmu = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001808 uint32_t ccb_post_stamp, arc_cdb_size;
1809
1810 arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
Ching Huang626fa322014-08-19 15:10:12 +08001811 ccb_post_stamp = (cdb_phyaddr | ((arc_cdb_size - 1) >> 6) | 1);
Ching Huangc71ec552018-12-19 16:48:16 +08001812 writel(upper_32_bits(ccb->cdb_phyaddr), &phbcmu->inbound_queueport_high);
1813 writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001814 }
Ching Huang5b374792014-08-19 15:25:22 +08001815 break;
1816 case ACB_ADAPTER_TYPE_D: {
1817 struct MessageUnit_D *pmu = acb->pmuD;
1818 u16 index_stripped;
Ching Huang3b8155d2014-09-15 19:05:33 +08001819 u16 postq_index, toggle;
Ching Huang5b374792014-08-19 15:25:22 +08001820 unsigned long flags;
1821 struct InBound_SRB *pinbound_srb;
1822
1823 spin_lock_irqsave(&acb->postq_lock, flags);
1824 postq_index = pmu->postq_index;
1825 pinbound_srb = (struct InBound_SRB *)&(pmu->post_qbuffer[postq_index & 0xFF]);
Ching Huanga36ade42018-12-19 16:51:14 +08001826 pinbound_srb->addressHigh = upper_32_bits(ccb->cdb_phyaddr);
1827 pinbound_srb->addressLow = cdb_phyaddr;
Ching Huang5b374792014-08-19 15:25:22 +08001828 pinbound_srb->length = ccb->arc_cdb_size >> 2;
1829 arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
Ching Huang3b8155d2014-09-15 19:05:33 +08001830 toggle = postq_index & 0x4000;
1831 index_stripped = postq_index + 1;
1832 index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1);
1833 pmu->postq_index = index_stripped ? (index_stripped | toggle) :
1834 (toggle ^ 0x4000);
Ching Huang5b374792014-08-19 15:25:22 +08001835 writel(postq_index, pmu->inboundlist_write_pointer);
1836 spin_unlock_irqrestore(&acb->postq_lock, flags);
1837 break;
1838 }
Ching Huang23509022017-12-05 09:35:34 +08001839 case ACB_ADAPTER_TYPE_E: {
1840 struct MessageUnit_E __iomem *pmu = acb->pmuE;
1841 u32 ccb_post_stamp, arc_cdb_size;
1842
1843 arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
1844 ccb_post_stamp = (ccb->smid | ((arc_cdb_size - 1) >> 6));
1845 writel(0, &pmu->inbound_queueport_high);
1846 writel(ccb_post_stamp, &pmu->inbound_queueport_low);
1847 break;
1848 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001849 }
Erich Chen1c57e862006-07-12 08:59:32 -07001850}
1851
Ching Huang626fa322014-08-19 15:10:12 +08001852static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001853{
Al Viro80da1ad2007-10-29 05:08:28 +00001854 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001855 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
1856 writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
Ching Huang626fa322014-08-19 15:10:12 +08001857 if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001858 printk(KERN_NOTICE
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02001859 "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
Nick Cheng1a4f5502007-09-13 17:26:40 +08001860 , acb->host->host_no);
1861 }
1862}
1863
Ching Huang626fa322014-08-19 15:10:12 +08001864static void arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001865{
Al Viro80da1ad2007-10-29 05:08:28 +00001866 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001867 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001868 writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001869
Ching Huang626fa322014-08-19 15:10:12 +08001870 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001871 printk(KERN_NOTICE
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02001872 "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
Nick Cheng1a4f5502007-09-13 17:26:40 +08001873 , acb->host->host_no);
Erich Chen1c57e862006-07-12 08:59:32 -07001874 }
1875}
1876
Ching Huang626fa322014-08-19 15:10:12 +08001877static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08001878{
Ching Huangc10b1d52014-08-19 15:20:31 +08001879 struct MessageUnit_C __iomem *reg = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001880 pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
1881 writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
1882 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08001883 if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08001884 printk(KERN_NOTICE
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02001885 "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
Nick Chengcdd3cb12010-07-13 20:03:04 +08001886 , pACB->host->host_no);
1887 }
1888 return;
1889}
Ching Huang5b374792014-08-19 15:25:22 +08001890
1891static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB)
1892{
1893 struct MessageUnit_D *reg = pACB->pmuD;
1894
1895 pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
1896 writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, reg->inbound_msgaddr0);
1897 if (!arcmsr_hbaD_wait_msgint_ready(pACB))
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02001898 pr_notice("arcmsr%d: wait 'stop adapter background rebuild' "
Ching Huang5b374792014-08-19 15:25:22 +08001899 "timeout\n", pACB->host->host_no);
1900}
1901
Ching Huang23509022017-12-05 09:35:34 +08001902static void arcmsr_hbaE_stop_bgrb(struct AdapterControlBlock *pACB)
1903{
1904 struct MessageUnit_E __iomem *reg = pACB->pmuE;
1905
1906 pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
1907 writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
1908 pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
1909 writel(pACB->out_doorbell, &reg->iobound_doorbell);
1910 if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02001911 pr_notice("arcmsr%d: wait 'stop adapter background rebuild' "
Ching Huang23509022017-12-05 09:35:34 +08001912 "timeout\n", pACB->host->host_no);
1913 }
1914}
1915
Erich Chen1c57e862006-07-12 08:59:32 -07001916static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
1917{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001918 switch (acb->adapter_type) {
1919 case ACB_ADAPTER_TYPE_A: {
Ching Huang626fa322014-08-19 15:10:12 +08001920 arcmsr_hbaA_stop_bgrb(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001921 }
1922 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001923
Nick Cheng1a4f5502007-09-13 17:26:40 +08001924 case ACB_ADAPTER_TYPE_B: {
Ching Huang626fa322014-08-19 15:10:12 +08001925 arcmsr_hbaB_stop_bgrb(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001926 }
1927 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001928 case ACB_ADAPTER_TYPE_C: {
Ching Huang626fa322014-08-19 15:10:12 +08001929 arcmsr_hbaC_stop_bgrb(acb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08001930 }
Ching Huang5b374792014-08-19 15:25:22 +08001931 break;
1932 case ACB_ADAPTER_TYPE_D:
1933 arcmsr_hbaD_stop_bgrb(acb);
1934 break;
Ching Huang23509022017-12-05 09:35:34 +08001935 case ACB_ADAPTER_TYPE_E:
1936 arcmsr_hbaE_stop_bgrb(acb);
1937 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001938 }
Erich Chen1c57e862006-07-12 08:59:32 -07001939}
1940
1941static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
1942{
Nick Chengcdd3cb12010-07-13 20:03:04 +08001943 dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
Erich Chen1c57e862006-07-12 08:59:32 -07001944}
1945
Ching Huangc10b1d52014-08-19 15:20:31 +08001946static void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001947{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001948 switch (acb->adapter_type) {
1949 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001950 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001951 writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
1952 }
1953 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001954
Nick Cheng1a4f5502007-09-13 17:26:40 +08001955 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001956 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001957 writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001958 }
1959 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08001960 case ACB_ADAPTER_TYPE_C: {
1961 struct MessageUnit_C __iomem *reg = acb->pmuC;
Ching Huang5b374792014-08-19 15:25:22 +08001962
Nick Chengcdd3cb12010-07-13 20:03:04 +08001963 writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
1964 }
Ching Huang5b374792014-08-19 15:25:22 +08001965 break;
1966 case ACB_ADAPTER_TYPE_D: {
1967 struct MessageUnit_D *reg = acb->pmuD;
1968 writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
1969 reg->inbound_doorbell);
1970 }
1971 break;
Ching Huang23509022017-12-05 09:35:34 +08001972 case ACB_ADAPTER_TYPE_E: {
1973 struct MessageUnit_E __iomem *reg = acb->pmuE;
1974 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
1975 writel(acb->out_doorbell, &reg->iobound_doorbell);
1976 }
1977 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001978 }
1979}
1980
1981static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
1982{
1983 switch (acb->adapter_type) {
1984 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001985 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001986 /*
1987 ** push inbound doorbell tell iop, driver data write ok
1988 ** and wait reply on next hwinterrupt for next Qbuffer post
1989 */
1990 writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
1991 }
1992 break;
1993
1994 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001995 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001996 /*
1997 ** push inbound doorbell tell iop, driver data write ok
1998 ** and wait reply on next hwinterrupt for next Qbuffer post
1999 */
Nick Chengae52e7f2010-06-18 15:39:12 +08002000 writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002001 }
2002 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002003 case ACB_ADAPTER_TYPE_C: {
2004 struct MessageUnit_C __iomem *reg = acb->pmuC;
2005 /*
2006 ** push inbound doorbell tell iop, driver data write ok
2007 ** and wait reply on next hwinterrupt for next Qbuffer post
2008 */
2009 writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, &reg->inbound_doorbell);
2010 }
2011 break;
Ching Huang5b374792014-08-19 15:25:22 +08002012 case ACB_ADAPTER_TYPE_D: {
2013 struct MessageUnit_D *reg = acb->pmuD;
2014 writel(ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY,
2015 reg->inbound_doorbell);
2016 }
2017 break;
Ching Huang23509022017-12-05 09:35:34 +08002018 case ACB_ADAPTER_TYPE_E: {
2019 struct MessageUnit_E __iomem *reg = acb->pmuE;
2020 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_WRITE_OK;
2021 writel(acb->out_doorbell, &reg->iobound_doorbell);
2022 }
2023 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002024 }
2025}
2026
Al Viro80da1ad2007-10-29 05:08:28 +00002027struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002028{
Al Viro0c7eb2e2007-10-29 05:08:58 +00002029 struct QBUFFER __iomem *qbuffer = NULL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002030 switch (acb->adapter_type) {
2031
2032 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00002033 struct MessageUnit_A __iomem *reg = acb->pmuA;
2034 qbuffer = (struct QBUFFER __iomem *)&reg->message_rbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002035 }
2036 break;
2037
2038 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00002039 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002040 qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002041 }
2042 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002043 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08002044 struct MessageUnit_C __iomem *phbcmu = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002045 qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
2046 }
Ching Huang5b374792014-08-19 15:25:22 +08002047 break;
2048 case ACB_ADAPTER_TYPE_D: {
2049 struct MessageUnit_D *reg = acb->pmuD;
2050 qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
2051 }
2052 break;
Ching Huang23509022017-12-05 09:35:34 +08002053 case ACB_ADAPTER_TYPE_E: {
2054 struct MessageUnit_E __iomem *reg = acb->pmuE;
2055 qbuffer = (struct QBUFFER __iomem *)&reg->message_rbuffer;
2056 }
2057 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002058 }
2059 return qbuffer;
2060}
2061
Al Viro80da1ad2007-10-29 05:08:28 +00002062static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002063{
Al Viro0c7eb2e2007-10-29 05:08:58 +00002064 struct QBUFFER __iomem *pqbuffer = NULL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002065 switch (acb->adapter_type) {
2066
2067 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00002068 struct MessageUnit_A __iomem *reg = acb->pmuA;
2069 pqbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002070 }
2071 break;
2072
2073 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00002074 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002075 pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002076 }
2077 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002078 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08002079 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002080 pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
Ching Huang5b374792014-08-19 15:25:22 +08002081 }
2082 break;
2083 case ACB_ADAPTER_TYPE_D: {
2084 struct MessageUnit_D *reg = acb->pmuD;
2085 pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
2086 }
2087 break;
Ching Huang23509022017-12-05 09:35:34 +08002088 case ACB_ADAPTER_TYPE_E: {
2089 struct MessageUnit_E __iomem *reg = acb->pmuE;
2090 pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
2091 }
2092 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002093 }
2094 return pqbuffer;
2095}
2096
Ching Huangbb263c42014-08-19 15:17:45 +08002097static uint32_t
2098arcmsr_Read_iop_rqbuffer_in_DWORD(struct AdapterControlBlock *acb,
2099 struct QBUFFER __iomem *prbuffer)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002100{
Ching Huangbb263c42014-08-19 15:17:45 +08002101 uint8_t *pQbuffer;
2102 uint8_t *buf1 = NULL;
2103 uint32_t __iomem *iop_data;
2104 uint32_t iop_len, data_len, *buf2 = NULL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002105
Ching Huangbb263c42014-08-19 15:17:45 +08002106 iop_data = (uint32_t __iomem *)prbuffer->data;
2107 iop_len = readl(&prbuffer->data_len);
2108 if (iop_len > 0) {
2109 buf1 = kmalloc(128, GFP_ATOMIC);
2110 buf2 = (uint32_t *)buf1;
2111 if (buf1 == NULL)
2112 return 0;
2113 data_len = iop_len;
2114 while (data_len >= 4) {
2115 *buf2++ = readl(iop_data);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002116 iop_data++;
Ching Huangbb263c42014-08-19 15:17:45 +08002117 data_len -= 4;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002118 }
Ching Huangbb263c42014-08-19 15:17:45 +08002119 if (data_len)
2120 *buf2 = readl(iop_data);
2121 buf2 = (uint32_t *)buf1;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002122 }
Ching Huangbb263c42014-08-19 15:17:45 +08002123 while (iop_len > 0) {
Ching Huang2e9feb42014-09-24 17:33:34 +08002124 pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex];
Ching Huangbb263c42014-08-19 15:17:45 +08002125 *pQbuffer = *buf1;
Ching Huang2e9feb42014-09-24 17:33:34 +08002126 acb->rqbuf_putIndex++;
Ching Huangbb263c42014-08-19 15:17:45 +08002127 /* if last, index number set it to 0 */
Ching Huang2e9feb42014-09-24 17:33:34 +08002128 acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER;
Ching Huangbb263c42014-08-19 15:17:45 +08002129 buf1++;
2130 iop_len--;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002131 }
Ching Huang2e9feb42014-09-24 17:33:34 +08002132 kfree(buf2);
Ching Huangbb263c42014-08-19 15:17:45 +08002133 /* let IOP know data has been read */
2134 arcmsr_iop_message_read(acb);
2135 return 1;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002136}
2137
Ching Huangbb263c42014-08-19 15:17:45 +08002138uint32_t
2139arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb,
2140 struct QBUFFER __iomem *prbuffer) {
2141
2142 uint8_t *pQbuffer;
2143 uint8_t __iomem *iop_data;
2144 uint32_t iop_len;
2145
Ching Huang52b4dab2017-12-05 09:28:04 +08002146 if (acb->adapter_type > ACB_ADAPTER_TYPE_B)
Ching Huangbb263c42014-08-19 15:17:45 +08002147 return arcmsr_Read_iop_rqbuffer_in_DWORD(acb, prbuffer);
2148 iop_data = (uint8_t __iomem *)prbuffer->data;
2149 iop_len = readl(&prbuffer->data_len);
2150 while (iop_len > 0) {
Ching Huang2e9feb42014-09-24 17:33:34 +08002151 pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex];
Ching Huangbb263c42014-08-19 15:17:45 +08002152 *pQbuffer = readb(iop_data);
Ching Huang2e9feb42014-09-24 17:33:34 +08002153 acb->rqbuf_putIndex++;
2154 acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER;
Ching Huangbb263c42014-08-19 15:17:45 +08002155 iop_data++;
2156 iop_len--;
2157 }
2158 arcmsr_iop_message_read(acb);
2159 return 1;
2160}
2161
2162static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002163{
Ching Huangbb263c42014-08-19 15:17:45 +08002164 unsigned long flags;
2165 struct QBUFFER __iomem *prbuffer;
2166 int32_t buf_empty_len;
2167
2168 spin_lock_irqsave(&acb->rqbuffer_lock, flags);
2169 prbuffer = arcmsr_get_iop_rqbuffer(acb);
Ching Huang2e9feb42014-09-24 17:33:34 +08002170 buf_empty_len = (acb->rqbuf_putIndex - acb->rqbuf_getIndex - 1) &
Ching Huangbb263c42014-08-19 15:17:45 +08002171 (ARCMSR_MAX_QBUFFER - 1);
2172 if (buf_empty_len >= readl(&prbuffer->data_len)) {
2173 if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
2174 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
2175 } else
2176 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
2177 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
2178}
2179
2180static void arcmsr_write_ioctldata2iop_in_DWORD(struct AdapterControlBlock *acb)
2181{
2182 uint8_t *pQbuffer;
2183 struct QBUFFER __iomem *pwbuffer;
2184 uint8_t *buf1 = NULL;
2185 uint32_t __iomem *iop_data;
2186 uint32_t allxfer_len = 0, data_len, *buf2 = NULL, data;
2187
2188 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
2189 buf1 = kmalloc(128, GFP_ATOMIC);
2190 buf2 = (uint32_t *)buf1;
2191 if (buf1 == NULL)
2192 return;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002193
2194 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
2195 pwbuffer = arcmsr_get_iop_wqbuffer(acb);
Ching Huangbb263c42014-08-19 15:17:45 +08002196 iop_data = (uint32_t __iomem *)pwbuffer->data;
Ching Huang2e9feb42014-09-24 17:33:34 +08002197 while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex)
Ching Huangbb263c42014-08-19 15:17:45 +08002198 && (allxfer_len < 124)) {
Ching Huang2e9feb42014-09-24 17:33:34 +08002199 pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex];
Ching Huangbb263c42014-08-19 15:17:45 +08002200 *buf1 = *pQbuffer;
Ching Huang2e9feb42014-09-24 17:33:34 +08002201 acb->wqbuf_getIndex++;
2202 acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER;
Ching Huangbb263c42014-08-19 15:17:45 +08002203 buf1++;
2204 allxfer_len++;
2205 }
2206 data_len = allxfer_len;
2207 buf1 = (uint8_t *)buf2;
2208 while (data_len >= 4) {
2209 data = *buf2++;
2210 writel(data, iop_data);
2211 iop_data++;
2212 data_len -= 4;
2213 }
2214 if (data_len) {
2215 data = *buf2;
2216 writel(data, iop_data);
2217 }
2218 writel(allxfer_len, &pwbuffer->data_len);
2219 kfree(buf1);
2220 arcmsr_iop_message_wrote(acb);
2221 }
2222}
2223
2224void
2225arcmsr_write_ioctldata2iop(struct AdapterControlBlock *acb)
2226{
2227 uint8_t *pQbuffer;
2228 struct QBUFFER __iomem *pwbuffer;
2229 uint8_t __iomem *iop_data;
2230 int32_t allxfer_len = 0;
2231
Ching Huang52b4dab2017-12-05 09:28:04 +08002232 if (acb->adapter_type > ACB_ADAPTER_TYPE_B) {
Ching Huangbb263c42014-08-19 15:17:45 +08002233 arcmsr_write_ioctldata2iop_in_DWORD(acb);
2234 return;
2235 }
2236 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
2237 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
2238 pwbuffer = arcmsr_get_iop_wqbuffer(acb);
2239 iop_data = (uint8_t __iomem *)pwbuffer->data;
Ching Huang2e9feb42014-09-24 17:33:34 +08002240 while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex)
Ching Huangbb263c42014-08-19 15:17:45 +08002241 && (allxfer_len < 124)) {
Ching Huang2e9feb42014-09-24 17:33:34 +08002242 pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex];
Ching Huangbb263c42014-08-19 15:17:45 +08002243 writeb(*pQbuffer, iop_data);
Ching Huang2e9feb42014-09-24 17:33:34 +08002244 acb->wqbuf_getIndex++;
2245 acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002246 iop_data++;
2247 allxfer_len++;
2248 }
Ching Huangbb263c42014-08-19 15:17:45 +08002249 writel(allxfer_len, &pwbuffer->data_len);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002250 arcmsr_iop_message_wrote(acb);
2251 }
Ching Huangbb263c42014-08-19 15:17:45 +08002252}
Nick Cheng1a4f5502007-09-13 17:26:40 +08002253
Ching Huangbb263c42014-08-19 15:17:45 +08002254static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
2255{
2256 unsigned long flags;
2257
2258 spin_lock_irqsave(&acb->wqbuffer_lock, flags);
2259 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
Ching Huang2e9feb42014-09-24 17:33:34 +08002260 if (acb->wqbuf_getIndex != acb->wqbuf_putIndex)
Ching Huangbb263c42014-08-19 15:17:45 +08002261 arcmsr_write_ioctldata2iop(acb);
Ching Huang2e9feb42014-09-24 17:33:34 +08002262 if (acb->wqbuf_getIndex == acb->wqbuf_putIndex)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002263 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
Ching Huangbb263c42014-08-19 15:17:45 +08002264 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002265}
2266
Ching Huang626fa322014-08-19 15:10:12 +08002267static void arcmsr_hbaA_doorbell_isr(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002268{
2269 uint32_t outbound_doorbell;
Al Viro80da1ad2007-10-29 05:08:28 +00002270 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002271 outbound_doorbell = readl(&reg->outbound_doorbell);
Ching Huang6b393722014-08-19 14:18:24 +08002272 do {
2273 writel(outbound_doorbell, &reg->outbound_doorbell);
2274 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
2275 arcmsr_iop2drv_data_wrote_handle(acb);
2276 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
2277 arcmsr_iop2drv_data_read_handle(acb);
2278 outbound_doorbell = readl(&reg->outbound_doorbell);
2279 } while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
2280 | ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
Nick Cheng1a4f5502007-09-13 17:26:40 +08002281}
Ching Huang626fa322014-08-19 15:10:12 +08002282static void arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08002283{
2284 uint32_t outbound_doorbell;
Ching Huangc10b1d52014-08-19 15:20:31 +08002285 struct MessageUnit_C __iomem *reg = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002286 /*
2287 *******************************************************************
2288 ** Maybe here we need to check wrqbuffer_lock is lock or not
2289 ** DOORBELL: din! don!
2290 ** check if there are any mail need to pack from firmware
2291 *******************************************************************
2292 */
2293 outbound_doorbell = readl(&reg->outbound_doorbell);
Ching Huang6b393722014-08-19 14:18:24 +08002294 do {
2295 writel(outbound_doorbell, &reg->outbound_doorbell_clear);
2296 readl(&reg->outbound_doorbell_clear);
2297 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK)
2298 arcmsr_iop2drv_data_wrote_handle(pACB);
2299 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK)
2300 arcmsr_iop2drv_data_read_handle(pACB);
2301 if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)
Ching Huang626fa322014-08-19 15:10:12 +08002302 arcmsr_hbaC_message_isr(pACB);
Ching Huang6b393722014-08-19 14:18:24 +08002303 outbound_doorbell = readl(&reg->outbound_doorbell);
2304 } while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK
2305 | ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
2306 | ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
Nick Chengcdd3cb12010-07-13 20:03:04 +08002307}
Ching Huang5b374792014-08-19 15:25:22 +08002308
2309static void arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB)
2310{
2311 uint32_t outbound_doorbell;
2312 struct MessageUnit_D *pmu = pACB->pmuD;
2313
2314 outbound_doorbell = readl(pmu->outbound_doorbell);
2315 do {
2316 writel(outbound_doorbell, pmu->outbound_doorbell);
2317 if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE)
2318 arcmsr_hbaD_message_isr(pACB);
2319 if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK)
2320 arcmsr_iop2drv_data_wrote_handle(pACB);
2321 if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK)
2322 arcmsr_iop2drv_data_read_handle(pACB);
2323 outbound_doorbell = readl(pmu->outbound_doorbell);
2324 } while (outbound_doorbell & (ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK
2325 | ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK
2326 | ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE));
2327}
2328
Ching Huang23509022017-12-05 09:35:34 +08002329static void arcmsr_hbaE_doorbell_isr(struct AdapterControlBlock *pACB)
2330{
2331 uint32_t outbound_doorbell, in_doorbell, tmp;
2332 struct MessageUnit_E __iomem *reg = pACB->pmuE;
2333
2334 in_doorbell = readl(&reg->iobound_doorbell);
2335 outbound_doorbell = in_doorbell ^ pACB->in_doorbell;
2336 do {
2337 writel(0, &reg->host_int_status); /* clear interrupt */
2338 if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK) {
2339 arcmsr_iop2drv_data_wrote_handle(pACB);
2340 }
2341 if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK) {
2342 arcmsr_iop2drv_data_read_handle(pACB);
2343 }
2344 if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
2345 arcmsr_hbaE_message_isr(pACB);
2346 }
2347 tmp = in_doorbell;
2348 in_doorbell = readl(&reg->iobound_doorbell);
2349 outbound_doorbell = tmp ^ in_doorbell;
2350 } while (outbound_doorbell & (ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK
2351 | ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK
2352 | ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE));
2353 pACB->in_doorbell = in_doorbell;
2354}
2355
Ching Huang626fa322014-08-19 15:10:12 +08002356static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002357{
2358 uint32_t flag_ccb;
Al Viro80da1ad2007-10-29 05:08:28 +00002359 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002360 struct ARCMSR_CDB *pARCMSR_CDB;
2361 struct CommandControlBlock *pCCB;
2362 bool error;
Ching Huang9e386a52018-12-19 16:43:15 +08002363 unsigned long cdb_phy_addr;
2364
Nick Cheng1a4f5502007-09-13 17:26:40 +08002365 while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
Ching Huang9e386a52018-12-19 16:43:15 +08002366 cdb_phy_addr = (flag_ccb << 5) & 0xffffffff;
2367 if (acb->cdb_phyadd_hipart)
2368 cdb_phy_addr = cdb_phy_addr | acb->cdb_phyadd_hipart;
2369 pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + cdb_phy_addr);
Nick Chengcdd3cb12010-07-13 20:03:04 +08002370 pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
2371 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
2372 arcmsr_drain_donequeue(acb, pCCB, error);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002373 }
2374}
Ching Huang626fa322014-08-19 15:10:12 +08002375static void arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002376{
2377 uint32_t index;
2378 uint32_t flag_ccb;
Al Viro80da1ad2007-10-29 05:08:28 +00002379 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002380 struct ARCMSR_CDB *pARCMSR_CDB;
2381 struct CommandControlBlock *pCCB;
2382 bool error;
Ching Huange66764f2018-12-19 16:45:46 +08002383 unsigned long cdb_phy_addr;
2384
Nick Cheng1a4f5502007-09-13 17:26:40 +08002385 index = reg->doneq_index;
Ching Huangc10b1d52014-08-19 15:20:31 +08002386 while ((flag_ccb = reg->done_qbuffer[index]) != 0) {
Ching Huange66764f2018-12-19 16:45:46 +08002387 cdb_phy_addr = (flag_ccb << 5) & 0xffffffff;
2388 if (acb->cdb_phyadd_hipart)
2389 cdb_phy_addr = cdb_phy_addr | acb->cdb_phyadd_hipart;
2390 pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + cdb_phy_addr);
Nick Chengcdd3cb12010-07-13 20:03:04 +08002391 pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
2392 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
2393 arcmsr_drain_donequeue(acb, pCCB, error);
Ching Huange66764f2018-12-19 16:45:46 +08002394 reg->done_qbuffer[index] = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002395 index++;
2396 index %= ARCMSR_MAX_HBB_POSTQUEUE;
2397 reg->doneq_index = index;
2398 }
2399}
Nick Chengcdd3cb12010-07-13 20:03:04 +08002400
Ching Huang626fa322014-08-19 15:10:12 +08002401static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb)
Nick Chengcdd3cb12010-07-13 20:03:04 +08002402{
Ching Huangc10b1d52014-08-19 15:20:31 +08002403 struct MessageUnit_C __iomem *phbcmu;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002404 struct ARCMSR_CDB *arcmsr_cdb;
2405 struct CommandControlBlock *ccb;
Ching Huangc71ec552018-12-19 16:48:16 +08002406 uint32_t flag_ccb, throttling = 0;
2407 unsigned long ccb_cdb_phy;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002408 int error;
2409
Ching Huangc10b1d52014-08-19 15:20:31 +08002410 phbcmu = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002411 /* areca cdb command done */
2412 /* Use correct offset and size for syncing */
2413
Ching Huang6b393722014-08-19 14:18:24 +08002414 while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) !=
2415 0xFFFFFFFF) {
2416 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
Ching Huangc71ec552018-12-19 16:48:16 +08002417 if (acb->cdb_phyadd_hipart)
2418 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
Ching Huang6b393722014-08-19 14:18:24 +08002419 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
2420 + ccb_cdb_phy);
2421 ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
2422 arcmsr_cdb);
2423 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
2424 ? true : false;
2425 /* check if command done with no error */
2426 arcmsr_drain_donequeue(acb, ccb, error);
2427 throttling++;
2428 if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
2429 writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING,
2430 &phbcmu->inbound_doorbell);
2431 throttling = 0;
2432 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08002433 }
2434}
Ching Huang5b374792014-08-19 15:25:22 +08002435
2436static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb)
2437{
Ching Huang3b8155d2014-09-15 19:05:33 +08002438 u32 outbound_write_pointer, doneq_index, index_stripped, toggle;
Ching Huanga36ade42018-12-19 16:51:14 +08002439 uint32_t addressLow;
Ching Huang5b374792014-08-19 15:25:22 +08002440 int error;
2441 struct MessageUnit_D *pmu;
2442 struct ARCMSR_CDB *arcmsr_cdb;
2443 struct CommandControlBlock *ccb;
Lee Jones18bc4352020-07-13 08:46:30 +01002444 unsigned long flags, ccb_cdb_phy;
Ching Huang5b374792014-08-19 15:25:22 +08002445
2446 spin_lock_irqsave(&acb->doneq_lock, flags);
2447 pmu = acb->pmuD;
2448 outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
2449 doneq_index = pmu->doneq_index;
2450 if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
2451 do {
Ching Huang3b8155d2014-09-15 19:05:33 +08002452 toggle = doneq_index & 0x4000;
2453 index_stripped = (doneq_index & 0xFFF) + 1;
2454 index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
2455 pmu->doneq_index = index_stripped ? (index_stripped | toggle) :
2456 ((toggle ^ 0x4000) + 1);
Ching Huang5b374792014-08-19 15:25:22 +08002457 doneq_index = pmu->doneq_index;
2458 addressLow = pmu->done_qbuffer[doneq_index &
2459 0xFFF].addressLow;
2460 ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
Ching Huanga36ade42018-12-19 16:51:14 +08002461 if (acb->cdb_phyadd_hipart)
2462 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
Ching Huang5b374792014-08-19 15:25:22 +08002463 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
2464 + ccb_cdb_phy);
2465 ccb = container_of(arcmsr_cdb,
2466 struct CommandControlBlock, arcmsr_cdb);
2467 error = (addressLow & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
2468 ? true : false;
2469 arcmsr_drain_donequeue(acb, ccb, error);
2470 writel(doneq_index, pmu->outboundlist_read_pointer);
2471 } while ((doneq_index & 0xFFF) !=
2472 (outbound_write_pointer & 0xFFF));
2473 }
2474 writel(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
2475 pmu->outboundlist_interrupt_cause);
2476 readl(pmu->outboundlist_interrupt_cause);
2477 spin_unlock_irqrestore(&acb->doneq_lock, flags);
2478}
2479
Ching Huang23509022017-12-05 09:35:34 +08002480static void arcmsr_hbaE_postqueue_isr(struct AdapterControlBlock *acb)
2481{
2482 uint32_t doneq_index;
2483 uint16_t cmdSMID;
2484 int error;
2485 struct MessageUnit_E __iomem *pmu;
2486 struct CommandControlBlock *ccb;
2487 unsigned long flags;
2488
2489 spin_lock_irqsave(&acb->doneq_lock, flags);
2490 doneq_index = acb->doneq_index;
2491 pmu = acb->pmuE;
2492 while ((readl(&pmu->reply_post_producer_index) & 0xFFFF) != doneq_index) {
2493 cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
2494 ccb = acb->pccb_pool[cmdSMID];
2495 error = (acb->pCompletionQ[doneq_index].cmdFlag
2496 & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
2497 arcmsr_drain_donequeue(acb, ccb, error);
2498 doneq_index++;
2499 if (doneq_index >= acb->completionQ_entry)
2500 doneq_index = 0;
2501 }
2502 acb->doneq_index = doneq_index;
2503 writel(doneq_index, &pmu->reply_post_consumer_index);
2504 spin_unlock_irqrestore(&acb->doneq_lock, flags);
2505}
2506
Nick Cheng36b83de2010-05-17 11:22:42 +08002507/*
2508**********************************************************************************
2509** Handle a message interrupt
2510**
Nick Chengcdd3cb12010-07-13 20:03:04 +08002511** The only message interrupt we expect is in response to a query for the current adapter config.
Nick Cheng36b83de2010-05-17 11:22:42 +08002512** We want this in order to compare the drivemap so that we can detect newly-attached drives.
2513**********************************************************************************
2514*/
Ching Huang626fa322014-08-19 15:10:12 +08002515static void arcmsr_hbaA_message_isr(struct AdapterControlBlock *acb)
Nick Cheng36b83de2010-05-17 11:22:42 +08002516{
Ching Huangc10b1d52014-08-19 15:20:31 +08002517 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +08002518 /*clear interrupt and message state*/
2519 writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
Ching Huang5dd8b3e2017-12-05 09:57:23 +08002520 if (acb->acb_flags & ACB_F_MSG_GET_CONFIG)
2521 schedule_work(&acb->arcmsr_do_message_isr_bh);
Nick Cheng36b83de2010-05-17 11:22:42 +08002522}
Ching Huang626fa322014-08-19 15:10:12 +08002523static void arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb)
Nick Cheng36b83de2010-05-17 11:22:42 +08002524{
2525 struct MessageUnit_B *reg = acb->pmuB;
2526
2527 /*clear interrupt and message state*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002528 writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
Ching Huang5dd8b3e2017-12-05 09:57:23 +08002529 if (acb->acb_flags & ACB_F_MSG_GET_CONFIG)
2530 schedule_work(&acb->arcmsr_do_message_isr_bh);
Nick Cheng36b83de2010-05-17 11:22:42 +08002531}
Nick Chengcdd3cb12010-07-13 20:03:04 +08002532/*
2533**********************************************************************************
2534** Handle a message interrupt
2535**
2536** The only message interrupt we expect is in response to a query for the
2537** current adapter config.
2538** We want this in order to compare the drivemap so that we can detect newly-attached drives.
2539**********************************************************************************
2540*/
Ching Huang626fa322014-08-19 15:10:12 +08002541static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *acb)
Nick Chengcdd3cb12010-07-13 20:03:04 +08002542{
Ching Huangc10b1d52014-08-19 15:20:31 +08002543 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002544 /*clear interrupt and message state*/
2545 writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);
Ching Huang5dd8b3e2017-12-05 09:57:23 +08002546 if (acb->acb_flags & ACB_F_MSG_GET_CONFIG)
2547 schedule_work(&acb->arcmsr_do_message_isr_bh);
Nick Chengcdd3cb12010-07-13 20:03:04 +08002548}
2549
Ching Huang5b374792014-08-19 15:25:22 +08002550static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb)
2551{
2552 struct MessageUnit_D *reg = acb->pmuD;
2553
2554 writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE, reg->outbound_doorbell);
2555 readl(reg->outbound_doorbell);
Ching Huang5dd8b3e2017-12-05 09:57:23 +08002556 if (acb->acb_flags & ACB_F_MSG_GET_CONFIG)
2557 schedule_work(&acb->arcmsr_do_message_isr_bh);
Ching Huang5b374792014-08-19 15:25:22 +08002558}
2559
Ching Huang23509022017-12-05 09:35:34 +08002560static void arcmsr_hbaE_message_isr(struct AdapterControlBlock *acb)
2561{
2562 struct MessageUnit_E __iomem *reg = acb->pmuE;
2563
2564 writel(0, &reg->host_int_status);
Ching Huang5dd8b3e2017-12-05 09:57:23 +08002565 if (acb->acb_flags & ACB_F_MSG_GET_CONFIG)
2566 schedule_work(&acb->arcmsr_do_message_isr_bh);
Ching Huang23509022017-12-05 09:35:34 +08002567}
2568
Ching Huang626fa322014-08-19 15:10:12 +08002569static int arcmsr_hbaA_handle_isr(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002570{
2571 uint32_t outbound_intstatus;
Al Viro80da1ad2007-10-29 05:08:28 +00002572 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +08002573 outbound_intstatus = readl(&reg->outbound_intstatus) &
Nick Chengcdd3cb12010-07-13 20:03:04 +08002574 acb->outbound_int_enable;
Ching Huang6b393722014-08-19 14:18:24 +08002575 if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
2576 return IRQ_NONE;
2577 do {
2578 writel(outbound_intstatus, &reg->outbound_intstatus);
2579 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
Ching Huang626fa322014-08-19 15:10:12 +08002580 arcmsr_hbaA_doorbell_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002581 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
Ching Huang626fa322014-08-19 15:10:12 +08002582 arcmsr_hbaA_postqueue_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002583 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
Ching Huang626fa322014-08-19 15:10:12 +08002584 arcmsr_hbaA_message_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002585 outbound_intstatus = readl(&reg->outbound_intstatus) &
2586 acb->outbound_int_enable;
2587 } while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT
2588 | ARCMSR_MU_OUTBOUND_POSTQUEUE_INT
2589 | ARCMSR_MU_OUTBOUND_MESSAGE0_INT));
2590 return IRQ_HANDLED;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002591}
2592
Ching Huang626fa322014-08-19 15:10:12 +08002593static int arcmsr_hbaB_handle_isr(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002594{
2595 uint32_t outbound_doorbell;
Al Viro80da1ad2007-10-29 05:08:28 +00002596 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002597 outbound_doorbell = readl(reg->iop2drv_doorbell) &
Nick Chengcdd3cb12010-07-13 20:03:04 +08002598 acb->outbound_int_enable;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002599 if (!outbound_doorbell)
Ching Huang6b393722014-08-19 14:18:24 +08002600 return IRQ_NONE;
2601 do {
2602 writel(~outbound_doorbell, reg->iop2drv_doorbell);
2603 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
2604 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
2605 arcmsr_iop2drv_data_wrote_handle(acb);
2606 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
2607 arcmsr_iop2drv_data_read_handle(acb);
2608 if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
Ching Huang626fa322014-08-19 15:10:12 +08002609 arcmsr_hbaB_postqueue_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002610 if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)
Ching Huang626fa322014-08-19 15:10:12 +08002611 arcmsr_hbaB_message_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002612 outbound_doorbell = readl(reg->iop2drv_doorbell) &
2613 acb->outbound_int_enable;
2614 } while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK
2615 | ARCMSR_IOP2DRV_DATA_READ_OK
2616 | ARCMSR_IOP2DRV_CDB_DONE
2617 | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE));
2618 return IRQ_HANDLED;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002619}
2620
Ching Huang626fa322014-08-19 15:10:12 +08002621static int arcmsr_hbaC_handle_isr(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08002622{
2623 uint32_t host_interrupt_status;
Ching Huangc10b1d52014-08-19 15:20:31 +08002624 struct MessageUnit_C __iomem *phbcmu = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002625 /*
2626 *********************************************
2627 ** check outbound intstatus
2628 *********************************************
2629 */
Ching Huang6b393722014-08-19 14:18:24 +08002630 host_interrupt_status = readl(&phbcmu->host_int_status) &
2631 (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
2632 ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR);
2633 if (!host_interrupt_status)
2634 return IRQ_NONE;
2635 do {
2636 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR)
Ching Huang626fa322014-08-19 15:10:12 +08002637 arcmsr_hbaC_doorbell_isr(pACB);
Ching Huang6b393722014-08-19 14:18:24 +08002638 /* MU post queue interrupts*/
2639 if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)
Ching Huang626fa322014-08-19 15:10:12 +08002640 arcmsr_hbaC_postqueue_isr(pACB);
Ching Huang6b393722014-08-19 14:18:24 +08002641 host_interrupt_status = readl(&phbcmu->host_int_status);
2642 } while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
2643 ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
2644 return IRQ_HANDLED;
Nick Chengcdd3cb12010-07-13 20:03:04 +08002645}
Ching Huang5b374792014-08-19 15:25:22 +08002646
2647static irqreturn_t arcmsr_hbaD_handle_isr(struct AdapterControlBlock *pACB)
2648{
2649 u32 host_interrupt_status;
2650 struct MessageUnit_D *pmu = pACB->pmuD;
2651
2652 host_interrupt_status = readl(pmu->host_int_status) &
2653 (ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR |
2654 ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR);
2655 if (!host_interrupt_status)
2656 return IRQ_NONE;
2657 do {
2658 /* MU post queue interrupts*/
2659 if (host_interrupt_status &
2660 ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR)
2661 arcmsr_hbaD_postqueue_isr(pACB);
2662 if (host_interrupt_status &
2663 ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR)
2664 arcmsr_hbaD_doorbell_isr(pACB);
2665 host_interrupt_status = readl(pmu->host_int_status);
2666 } while (host_interrupt_status &
2667 (ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR |
2668 ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR));
2669 return IRQ_HANDLED;
2670}
2671
Ching Huang23509022017-12-05 09:35:34 +08002672static irqreturn_t arcmsr_hbaE_handle_isr(struct AdapterControlBlock *pACB)
2673{
2674 uint32_t host_interrupt_status;
2675 struct MessageUnit_E __iomem *pmu = pACB->pmuE;
2676
2677 host_interrupt_status = readl(&pmu->host_int_status) &
2678 (ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
2679 ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR);
2680 if (!host_interrupt_status)
2681 return IRQ_NONE;
2682 do {
2683 /* MU ioctl transfer doorbell interrupts*/
2684 if (host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR) {
2685 arcmsr_hbaE_doorbell_isr(pACB);
2686 }
2687 /* MU post queue interrupts*/
2688 if (host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR) {
2689 arcmsr_hbaE_postqueue_isr(pACB);
2690 }
2691 host_interrupt_status = readl(&pmu->host_int_status);
2692 } while (host_interrupt_status & (ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
2693 ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR));
2694 return IRQ_HANDLED;
2695}
2696
Nick Cheng1a4f5502007-09-13 17:26:40 +08002697static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
2698{
2699 switch (acb->adapter_type) {
Ching Huang6b393722014-08-19 14:18:24 +08002700 case ACB_ADAPTER_TYPE_A:
Ching Huang626fa322014-08-19 15:10:12 +08002701 return arcmsr_hbaA_handle_isr(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002702 break;
Ching Huang6b393722014-08-19 14:18:24 +08002703 case ACB_ADAPTER_TYPE_B:
Ching Huang626fa322014-08-19 15:10:12 +08002704 return arcmsr_hbaB_handle_isr(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002705 break;
Ching Huang6b393722014-08-19 14:18:24 +08002706 case ACB_ADAPTER_TYPE_C:
Ching Huang626fa322014-08-19 15:10:12 +08002707 return arcmsr_hbaC_handle_isr(acb);
Ching Huang5b374792014-08-19 15:25:22 +08002708 case ACB_ADAPTER_TYPE_D:
2709 return arcmsr_hbaD_handle_isr(acb);
Ching Huang23509022017-12-05 09:35:34 +08002710 case ACB_ADAPTER_TYPE_E:
2711 return arcmsr_hbaE_handle_isr(acb);
Ching Huang6b393722014-08-19 14:18:24 +08002712 default:
2713 return IRQ_NONE;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002714 }
Erich Chen1c57e862006-07-12 08:59:32 -07002715}
2716
2717static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
2718{
2719 if (acb) {
2720 /* stop adapter background rebuild */
2721 if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002722 uint32_t intmask_org;
Erich Chen1c57e862006-07-12 08:59:32 -07002723 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002724 intmask_org = arcmsr_disable_outbound_ints(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07002725 arcmsr_stop_adapter_bgrb(acb);
2726 arcmsr_flush_adapter_cache(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002727 arcmsr_enable_outbound_ints(acb, intmask_org);
Erich Chen1c57e862006-07-12 08:59:32 -07002728 }
2729 }
2730}
2731
Ching Huangbb263c42014-08-19 15:17:45 +08002732
2733void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07002734{
Ching Huangbb263c42014-08-19 15:17:45 +08002735 uint32_t i;
2736
2737 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2738 for (i = 0; i < 15; i++) {
2739 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2740 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
Ching Huang2e9feb42014-09-24 17:33:34 +08002741 acb->rqbuf_getIndex = 0;
2742 acb->rqbuf_putIndex = 0;
Ching Huangbb263c42014-08-19 15:17:45 +08002743 arcmsr_iop_message_read(acb);
2744 mdelay(30);
Ching Huang2e9feb42014-09-24 17:33:34 +08002745 } else if (acb->rqbuf_getIndex !=
2746 acb->rqbuf_putIndex) {
2747 acb->rqbuf_getIndex = 0;
2748 acb->rqbuf_putIndex = 0;
Ching Huangbb263c42014-08-19 15:17:45 +08002749 mdelay(30);
2750 } else
2751 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002752 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002753 }
2754}
2755
Nick Cheng36b83de2010-05-17 11:22:42 +08002756static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
Ching Huangbb263c42014-08-19 15:17:45 +08002757 struct scsi_cmnd *cmd)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002758{
Erich Chen1c57e862006-07-12 08:59:32 -07002759 char *buffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002760 unsigned short use_sg;
2761 int retvalue = 0, transfer_len = 0;
2762 unsigned long flags;
2763 struct CMD_MESSAGE_FIELD *pcmdmessagefld;
2764 uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 |
2765 (uint32_t)cmd->cmnd[6] << 16 |
2766 (uint32_t)cmd->cmnd[7] << 8 |
2767 (uint32_t)cmd->cmnd[8];
FUJITA Tomonorideff2622007-05-14 19:25:56 +09002768 struct scatterlist *sg;
Ching Huangbb263c42014-08-19 15:17:45 +08002769
2770 use_sg = scsi_sg_count(cmd);
FUJITA Tomonorideff2622007-05-14 19:25:56 +09002771 sg = scsi_sglist(cmd);
Cong Wang77dfce02011-11-25 23:14:23 +08002772 buffer = kmap_atomic(sg_page(sg)) + sg->offset;
Ching Huangbb263c42014-08-19 15:17:45 +08002773 if (use_sg > 1) {
FUJITA Tomonorideff2622007-05-14 19:25:56 +09002774 retvalue = ARCMSR_MESSAGE_FAIL;
2775 goto message_out;
Erich Chen1c57e862006-07-12 08:59:32 -07002776 }
FUJITA Tomonorideff2622007-05-14 19:25:56 +09002777 transfer_len += sg->length;
Erich Chen1c57e862006-07-12 08:59:32 -07002778 if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
2779 retvalue = ARCMSR_MESSAGE_FAIL;
Ching Huangbb263c42014-08-19 15:17:45 +08002780 pr_info("%s: ARCMSR_MESSAGE_FAIL!\n", __func__);
Erich Chen1c57e862006-07-12 08:59:32 -07002781 goto message_out;
2782 }
Ching Huangbb263c42014-08-19 15:17:45 +08002783 pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer;
2784 switch (controlcode) {
Erich Chen1c57e862006-07-12 08:59:32 -07002785 case ARCMSR_MESSAGE_READ_RQBUFFER: {
Daniel Drake69e562c2008-02-20 13:29:05 +00002786 unsigned char *ver_addr;
Ching Huang2e9feb42014-09-24 17:33:34 +08002787 uint8_t *ptmpQbuffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002788 uint32_t allxfer_len = 0;
Ching Huang2e9feb42014-09-24 17:33:34 +08002789 ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
Daniel Drake69e562c2008-02-20 13:29:05 +00002790 if (!ver_addr) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002791 retvalue = ARCMSR_MESSAGE_FAIL;
Ching Huangbb263c42014-08-19 15:17:45 +08002792 pr_info("%s: memory not enough!\n", __func__);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002793 goto message_out;
2794 }
Daniel Drake69e562c2008-02-20 13:29:05 +00002795 ptmpQbuffer = ver_addr;
Ching Huangbb263c42014-08-19 15:17:45 +08002796 spin_lock_irqsave(&acb->rqbuffer_lock, flags);
Ching Huang2e9feb42014-09-24 17:33:34 +08002797 if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) {
2798 unsigned int tail = acb->rqbuf_getIndex;
2799 unsigned int head = acb->rqbuf_putIndex;
2800 unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER);
2801
2802 allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER);
2803 if (allxfer_len > ARCMSR_API_DATA_BUFLEN)
2804 allxfer_len = ARCMSR_API_DATA_BUFLEN;
2805
2806 if (allxfer_len <= cnt_to_end)
2807 memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len);
2808 else {
2809 memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end);
2810 memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end);
Ching Huangbb263c42014-08-19 15:17:45 +08002811 }
Ching Huang2e9feb42014-09-24 17:33:34 +08002812 acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002813 }
Ching Huangbb263c42014-08-19 15:17:45 +08002814 memcpy(pcmdmessagefld->messagedatabuffer, ver_addr,
2815 allxfer_len);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002816 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
Al Viro80da1ad2007-10-29 05:08:28 +00002817 struct QBUFFER __iomem *prbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002818 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
2819 prbuffer = arcmsr_get_iop_rqbuffer(acb);
Ching Huangbb263c42014-08-19 15:17:45 +08002820 if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
2821 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002822 }
Ching Huangbb263c42014-08-19 15:17:45 +08002823 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
Daniel Drake69e562c2008-02-20 13:29:05 +00002824 kfree(ver_addr);
Ching Huangbb263c42014-08-19 15:17:45 +08002825 pcmdmessagefld->cmdmessage.Length = allxfer_len;
2826 if (acb->fw_flag == FW_DEADLOCK)
2827 pcmdmessagefld->cmdmessage.ReturnCode =
2828 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2829 else
2830 pcmdmessagefld->cmdmessage.ReturnCode =
2831 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002832 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002833 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002834 case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
Daniel Drake69e562c2008-02-20 13:29:05 +00002835 unsigned char *ver_addr;
Dan Carpenter7bc2b552016-09-15 16:44:56 +03002836 uint32_t user_len;
2837 int32_t cnt2end;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002838 uint8_t *pQbuffer, *ptmpuserbuffer;
Borislav Petkov4bd173c2016-09-23 13:22:26 +02002839
2840 user_len = pcmdmessagefld->cmdmessage.Length;
2841 if (user_len > ARCMSR_API_DATA_BUFLEN) {
2842 retvalue = ARCMSR_MESSAGE_FAIL;
2843 goto message_out;
2844 }
2845
Ching Huang2e9feb42014-09-24 17:33:34 +08002846 ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
Daniel Drake69e562c2008-02-20 13:29:05 +00002847 if (!ver_addr) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002848 retvalue = ARCMSR_MESSAGE_FAIL;
2849 goto message_out;
2850 }
Daniel Drake69e562c2008-02-20 13:29:05 +00002851 ptmpuserbuffer = ver_addr;
Borislav Petkov4bd173c2016-09-23 13:22:26 +02002852
Ching Huangbb263c42014-08-19 15:17:45 +08002853 memcpy(ptmpuserbuffer,
2854 pcmdmessagefld->messagedatabuffer, user_len);
2855 spin_lock_irqsave(&acb->wqbuffer_lock, flags);
Ching Huang2e9feb42014-09-24 17:33:34 +08002856 if (acb->wqbuf_putIndex != acb->wqbuf_getIndex) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002857 struct SENSE_DATA *sensebuffer =
2858 (struct SENSE_DATA *)cmd->sense_buffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002859 arcmsr_write_ioctldata2iop(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002860 /* has error report sensedata */
Ching Huangbb263c42014-08-19 15:17:45 +08002861 sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002862 sensebuffer->SenseKey = ILLEGAL_REQUEST;
2863 sensebuffer->AdditionalSenseLength = 0x0A;
2864 sensebuffer->AdditionalSenseCode = 0x20;
2865 sensebuffer->Valid = 1;
2866 retvalue = ARCMSR_MESSAGE_FAIL;
2867 } else {
Ching Huang2e9feb42014-09-24 17:33:34 +08002868 pQbuffer = &acb->wqbuffer[acb->wqbuf_putIndex];
2869 cnt2end = ARCMSR_MAX_QBUFFER - acb->wqbuf_putIndex;
2870 if (user_len > cnt2end) {
2871 memcpy(pQbuffer, ptmpuserbuffer, cnt2end);
2872 ptmpuserbuffer += cnt2end;
2873 user_len -= cnt2end;
2874 acb->wqbuf_putIndex = 0;
2875 pQbuffer = acb->wqbuffer;
2876 }
2877 memcpy(pQbuffer, ptmpuserbuffer, user_len);
2878 acb->wqbuf_putIndex += user_len;
2879 acb->wqbuf_putIndex %= ARCMSR_MAX_QBUFFER;
2880 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
2881 acb->acb_flags &=
Nick Cheng1a4f5502007-09-13 17:26:40 +08002882 ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
Ching Huang2e9feb42014-09-24 17:33:34 +08002883 arcmsr_write_ioctldata2iop(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002884 }
Erich Chen1c57e862006-07-12 08:59:32 -07002885 }
Ching Huangbb263c42014-08-19 15:17:45 +08002886 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
2887 kfree(ver_addr);
2888 if (acb->fw_flag == FW_DEADLOCK)
2889 pcmdmessagefld->cmdmessage.ReturnCode =
2890 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2891 else
2892 pcmdmessagefld->cmdmessage.ReturnCode =
2893 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002894 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002895 }
Erich Chen1c57e862006-07-12 08:59:32 -07002896 case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002897 uint8_t *pQbuffer = acb->rqbuffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002898
2899 arcmsr_clear_iop2drv_rqueue_buffer(acb);
2900 spin_lock_irqsave(&acb->rqbuffer_lock, flags);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002901 acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
Ching Huang2e9feb42014-09-24 17:33:34 +08002902 acb->rqbuf_getIndex = 0;
2903 acb->rqbuf_putIndex = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002904 memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
Ching Huangbb263c42014-08-19 15:17:45 +08002905 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
2906 if (acb->fw_flag == FW_DEADLOCK)
Nick Chengae52e7f2010-06-18 15:39:12 +08002907 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002908 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2909 else
Nick Chengae52e7f2010-06-18 15:39:12 +08002910 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002911 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002912 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002913 }
Erich Chen1c57e862006-07-12 08:59:32 -07002914 case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002915 uint8_t *pQbuffer = acb->wqbuffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002916 spin_lock_irqsave(&acb->wqbuffer_lock, flags);
2917 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
2918 ACB_F_MESSAGE_WQBUFFER_READED);
Ching Huang2e9feb42014-09-24 17:33:34 +08002919 acb->wqbuf_getIndex = 0;
2920 acb->wqbuf_putIndex = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002921 memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
Ching Huangbb263c42014-08-19 15:17:45 +08002922 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
2923 if (acb->fw_flag == FW_DEADLOCK)
2924 pcmdmessagefld->cmdmessage.ReturnCode =
2925 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2926 else
2927 pcmdmessagefld->cmdmessage.ReturnCode =
2928 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002929 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002930 }
Erich Chen1c57e862006-07-12 08:59:32 -07002931 case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002932 uint8_t *pQbuffer;
Ching Huangbb263c42014-08-19 15:17:45 +08002933 arcmsr_clear_iop2drv_rqueue_buffer(acb);
2934 spin_lock_irqsave(&acb->rqbuffer_lock, flags);
2935 acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
Ching Huang2e9feb42014-09-24 17:33:34 +08002936 acb->rqbuf_getIndex = 0;
2937 acb->rqbuf_putIndex = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002938 pQbuffer = acb->rqbuffer;
2939 memset(pQbuffer, 0, sizeof(struct QBUFFER));
Ching Huangbb263c42014-08-19 15:17:45 +08002940 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
2941 spin_lock_irqsave(&acb->wqbuffer_lock, flags);
2942 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
2943 ACB_F_MESSAGE_WQBUFFER_READED);
Ching Huang2e9feb42014-09-24 17:33:34 +08002944 acb->wqbuf_getIndex = 0;
2945 acb->wqbuf_putIndex = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002946 pQbuffer = acb->wqbuffer;
2947 memset(pQbuffer, 0, sizeof(struct QBUFFER));
Ching Huangbb263c42014-08-19 15:17:45 +08002948 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
2949 if (acb->fw_flag == FW_DEADLOCK)
Nick Chengae52e7f2010-06-18 15:39:12 +08002950 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002951 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2952 else
Nick Chengae52e7f2010-06-18 15:39:12 +08002953 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002954 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002955 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002956 }
Erich Chen1c57e862006-07-12 08:59:32 -07002957 case ARCMSR_MESSAGE_RETURN_CODE_3F: {
Ching Huangbb263c42014-08-19 15:17:45 +08002958 if (acb->fw_flag == FW_DEADLOCK)
Nick Cheng36b83de2010-05-17 11:22:42 +08002959 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002960 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2961 else
Nick Chengae52e7f2010-06-18 15:39:12 +08002962 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002963 ARCMSR_MESSAGE_RETURNCODE_3F;
Erich Chen1c57e862006-07-12 08:59:32 -07002964 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002965 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002966 case ARCMSR_MESSAGE_SAY_HELLO: {
2967 int8_t *hello_string = "Hello! I am ARCMSR";
Ching Huangbb263c42014-08-19 15:17:45 +08002968 if (acb->fw_flag == FW_DEADLOCK)
Nick Cheng36b83de2010-05-17 11:22:42 +08002969 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002970 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2971 else
Nick Chengae52e7f2010-06-18 15:39:12 +08002972 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002973 ARCMSR_MESSAGE_RETURNCODE_OK;
2974 memcpy(pcmdmessagefld->messagedatabuffer,
2975 hello_string, (int16_t)strlen(hello_string));
Erich Chen1c57e862006-07-12 08:59:32 -07002976 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002977 }
2978 case ARCMSR_MESSAGE_SAY_GOODBYE: {
2979 if (acb->fw_flag == FW_DEADLOCK)
Nick Cheng36b83de2010-05-17 11:22:42 +08002980 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002981 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2982 else
2983 pcmdmessagefld->cmdmessage.ReturnCode =
2984 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002985 arcmsr_iop_parking(acb);
2986 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002987 }
2988 case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: {
2989 if (acb->fw_flag == FW_DEADLOCK)
Nick Cheng36b83de2010-05-17 11:22:42 +08002990 pcmdmessagefld->cmdmessage.ReturnCode =
Ching Huangbb263c42014-08-19 15:17:45 +08002991 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
2992 else
2993 pcmdmessagefld->cmdmessage.ReturnCode =
2994 ARCMSR_MESSAGE_RETURNCODE_OK;
Erich Chen1c57e862006-07-12 08:59:32 -07002995 arcmsr_flush_adapter_cache(acb);
2996 break;
Ching Huangbb263c42014-08-19 15:17:45 +08002997 }
Erich Chen1c57e862006-07-12 08:59:32 -07002998 default:
2999 retvalue = ARCMSR_MESSAGE_FAIL;
Ching Huangbb263c42014-08-19 15:17:45 +08003000 pr_info("%s: unknown controlcode!\n", __func__);
Erich Chen1c57e862006-07-12 08:59:32 -07003001 }
Ching Huangbb263c42014-08-19 15:17:45 +08003002message_out:
3003 if (use_sg) {
3004 struct scatterlist *sg = scsi_sglist(cmd);
3005 kunmap_atomic(buffer - sg->offset);
3006 }
Erich Chen1c57e862006-07-12 08:59:32 -07003007 return retvalue;
3008}
3009
3010static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
3011{
3012 struct list_head *head = &acb->ccb_free_list;
3013 struct CommandControlBlock *ccb = NULL;
Nick Chengae52e7f2010-06-18 15:39:12 +08003014 unsigned long flags;
3015 spin_lock_irqsave(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07003016 if (!list_empty(head)) {
3017 ccb = list_entry(head->next, struct CommandControlBlock, list);
Nick Chengae52e7f2010-06-18 15:39:12 +08003018 list_del_init(&ccb->list);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003019 }else{
Nick Chengae52e7f2010-06-18 15:39:12 +08003020 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Ching Huangc10b1d52014-08-19 15:20:31 +08003021 return NULL;
Erich Chen1c57e862006-07-12 08:59:32 -07003022 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003023 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07003024 return ccb;
3025}
3026
3027static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
3028 struct scsi_cmnd *cmd)
3029{
3030 switch (cmd->cmnd[0]) {
3031 case INQUIRY: {
3032 unsigned char inqdata[36];
3033 char *buffer;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09003034 struct scatterlist *sg;
Erich Chen1c57e862006-07-12 08:59:32 -07003035
3036 if (cmd->device->lun) {
3037 cmd->result = (DID_TIME_OUT << 16);
3038 cmd->scsi_done(cmd);
3039 return;
3040 }
3041 inqdata[0] = TYPE_PROCESSOR;
3042 /* Periph Qualifier & Periph Dev Type */
3043 inqdata[1] = 0;
3044 /* rem media bit & Dev Type Modifier */
3045 inqdata[2] = 0;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003046 /* ISO, ECMA, & ANSI versions */
Erich Chen1c57e862006-07-12 08:59:32 -07003047 inqdata[4] = 31;
3048 /* length of additional data */
3049 strncpy(&inqdata[8], "Areca ", 8);
3050 /* Vendor Identification */
3051 strncpy(&inqdata[16], "RAID controller ", 16);
3052 /* Product Identification */
3053 strncpy(&inqdata[32], "R001", 4); /* Product Revision */
Erich Chen1c57e862006-07-12 08:59:32 -07003054
FUJITA Tomonorideff2622007-05-14 19:25:56 +09003055 sg = scsi_sglist(cmd);
Cong Wang77dfce02011-11-25 23:14:23 +08003056 buffer = kmap_atomic(sg_page(sg)) + sg->offset;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09003057
Erich Chen1c57e862006-07-12 08:59:32 -07003058 memcpy(buffer, inqdata, sizeof(inqdata));
FUJITA Tomonorideff2622007-05-14 19:25:56 +09003059 sg = scsi_sglist(cmd);
Cong Wang77dfce02011-11-25 23:14:23 +08003060 kunmap_atomic(buffer - sg->offset);
Erich Chen1c57e862006-07-12 08:59:32 -07003061
Erich Chen1c57e862006-07-12 08:59:32 -07003062 cmd->scsi_done(cmd);
3063 }
3064 break;
3065 case WRITE_BUFFER:
3066 case READ_BUFFER: {
3067 if (arcmsr_iop_message_xfer(acb, cmd))
3068 cmd->result = (DID_ERROR << 16);
3069 cmd->scsi_done(cmd);
3070 }
3071 break;
3072 default:
3073 cmd->scsi_done(cmd);
3074 }
3075}
3076
Jeff Garzikf2812332010-11-16 02:10:29 -05003077static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
Erich Chen1c57e862006-07-12 08:59:32 -07003078 void (* done)(struct scsi_cmnd *))
3079{
3080 struct Scsi_Host *host = cmd->device->host;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003081 struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
Erich Chen1c57e862006-07-12 08:59:32 -07003082 struct CommandControlBlock *ccb;
3083 int target = cmd->device->id;
Ching Huangc4c1adb2018-03-15 14:33:36 +08003084
3085 if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) {
3086 cmd->result = (DID_NO_CONNECT << 16);
3087 cmd->scsi_done(cmd);
3088 return 0;
3089 }
Erich Chen1c57e862006-07-12 08:59:32 -07003090 cmd->scsi_done = done;
3091 cmd->host_scribble = NULL;
3092 cmd->result = 0;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003093 if (target == 16) {
Erich Chen1c57e862006-07-12 08:59:32 -07003094 /* virtual device for iop message transfer */
3095 arcmsr_handle_virtual_command(acb, cmd);
3096 return 0;
3097 }
Erich Chen1c57e862006-07-12 08:59:32 -07003098 ccb = arcmsr_get_freeccb(acb);
3099 if (!ccb)
3100 return SCSI_MLQUEUE_HOST_BUSY;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003101 if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
Nick Cheng76d78302008-02-04 23:53:24 -08003102 cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
3103 cmd->scsi_done(cmd);
3104 return 0;
3105 }
Erich Chen1c57e862006-07-12 08:59:32 -07003106 arcmsr_post_ccb(acb, ccb);
3107 return 0;
3108}
3109
Jeff Garzikf2812332010-11-16 02:10:29 -05003110static DEF_SCSI_QCMD(arcmsr_queue_command)
3111
Ching Huang1e9c8102017-12-12 18:53:33 +08003112static void arcmsr_get_adapter_config(struct AdapterControlBlock *pACB, uint32_t *rwbuffer)
3113{
3114 int count;
3115 uint32_t *acb_firm_model = (uint32_t *)pACB->firm_model;
3116 uint32_t *acb_firm_version = (uint32_t *)pACB->firm_version;
3117 uint32_t *acb_device_map = (uint32_t *)pACB->device_map;
3118 uint32_t *firm_model = &rwbuffer[15];
3119 uint32_t *firm_version = &rwbuffer[17];
3120 uint32_t *device_map = &rwbuffer[21];
3121
3122 count = 2;
3123 while (count) {
3124 *acb_firm_model = readl(firm_model);
3125 acb_firm_model++;
3126 firm_model++;
3127 count--;
3128 }
3129 count = 4;
3130 while (count) {
3131 *acb_firm_version = readl(firm_version);
3132 acb_firm_version++;
3133 firm_version++;
3134 count--;
3135 }
3136 count = 4;
3137 while (count) {
3138 *acb_device_map = readl(device_map);
3139 acb_device_map++;
3140 device_map++;
3141 count--;
3142 }
3143 pACB->signature = readl(&rwbuffer[0]);
3144 pACB->firm_request_len = readl(&rwbuffer[1]);
3145 pACB->firm_numbers_queue = readl(&rwbuffer[2]);
3146 pACB->firm_sdram_size = readl(&rwbuffer[3]);
3147 pACB->firm_hd_channels = readl(&rwbuffer[4]);
3148 pACB->firm_cfg_version = readl(&rwbuffer[25]);
3149 pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
3150 pACB->host->host_no,
3151 pACB->firm_model,
3152 pACB->firm_version);
3153}
3154
Ching Huang626fa322014-08-19 15:10:12 +08003155static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07003156{
Al Viro80da1ad2007-10-29 05:08:28 +00003157 struct MessageUnit_A __iomem *reg = acb->pmuA;
Ching Huang1e9c8102017-12-12 18:53:33 +08003158
Ching Huangb6b30842017-12-12 18:48:24 +08003159 arcmsr_wait_firmware_ready(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07003160 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
Ching Huang626fa322014-08-19 15:10:12 +08003161 if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08003162 printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
3163 miscellaneous data' timeout \n", acb->host->host_no);
Nick Chengae52e7f2010-06-18 15:39:12 +08003164 return false;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003165 }
Ching Huang1e9c8102017-12-12 18:53:33 +08003166 arcmsr_get_adapter_config(acb, reg->message_rwbuffer);
Nick Chengae52e7f2010-06-18 15:39:12 +08003167 return true;
Erich Chen1c57e862006-07-12 08:59:32 -07003168}
Ching Huang626fa322014-08-19 15:10:12 +08003169static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08003170{
Ching Huang02040672015-11-26 19:41:15 +08003171 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003172
Ching Huang7e315ff2015-11-25 19:49:33 +08003173 arcmsr_wait_firmware_ready(acb);
3174 writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
3175 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
3176 printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
Ching Huang02040672015-11-26 19:41:15 +08003177 return false;
Ching Huang7e315ff2015-11-25 19:49:33 +08003178 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003179 writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08003180 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08003181 printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
3182 miscellaneous data' timeout \n", acb->host->host_no);
Ching Huang02040672015-11-26 19:41:15 +08003183 return false;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003184 }
Ching Huang1e9c8102017-12-12 18:53:33 +08003185 arcmsr_get_adapter_config(acb, reg->message_rwbuffer);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003186 return true;
3187}
3188
Ching Huang626fa322014-08-19 15:10:12 +08003189static bool arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08003190{
Ching Huangdf9f0ee2017-12-12 18:42:29 +08003191 uint32_t intmask_org;
Ching Huangc10b1d52014-08-19 15:20:31 +08003192 struct MessageUnit_C __iomem *reg = pACB->pmuC;
Ching Huang1e9c8102017-12-12 18:53:33 +08003193
Nick Chengcdd3cb12010-07-13 20:03:04 +08003194 /* disable all outbound interrupt */
3195 intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
3196 writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
3197 /* wait firmware ready */
Ching Huangdf9f0ee2017-12-12 18:42:29 +08003198 arcmsr_wait_firmware_ready(pACB);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003199 /* post "get config" instruction */
3200 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
3201 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
3202 /* wait message ready */
Ching Huangdf9f0ee2017-12-12 18:42:29 +08003203 if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08003204 printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
3205 miscellaneous data' timeout \n", pACB->host->host_no);
3206 return false;
3207 }
Ching Huang1e9c8102017-12-12 18:53:33 +08003208 arcmsr_get_adapter_config(pACB, reg->msgcode_rwbuffer);
Nick Chengae52e7f2010-06-18 15:39:12 +08003209 return true;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003210}
Ching Huang5b374792014-08-19 15:25:22 +08003211
3212static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
3213{
Ching Huang02040672015-11-26 19:41:15 +08003214 struct MessageUnit_D *reg = acb->pmuD;
Ching Huang5b374792014-08-19 15:25:22 +08003215
Ching Huang5b374792014-08-19 15:25:22 +08003216 if (readl(acb->pmuD->outbound_doorbell) &
3217 ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
3218 writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
3219 acb->pmuD->outbound_doorbell);/*clear interrupt*/
3220 }
Ching Huangb6b30842017-12-12 18:48:24 +08003221 arcmsr_wait_firmware_ready(acb);
Ching Huang5b374792014-08-19 15:25:22 +08003222 /* post "get config" instruction */
3223 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, reg->inbound_msgaddr0);
3224 /* wait message ready */
3225 if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
3226 pr_notice("arcmsr%d: wait get adapter firmware "
3227 "miscellaneous data timeout\n", acb->host->host_no);
Ching Huang5b374792014-08-19 15:25:22 +08003228 return false;
3229 }
Ching Huang1e9c8102017-12-12 18:53:33 +08003230 arcmsr_get_adapter_config(acb, reg->msgcode_rwbuffer);
Ching Huang5b374792014-08-19 15:25:22 +08003231 return true;
3232}
3233
Ching Huang23509022017-12-05 09:35:34 +08003234static bool arcmsr_hbaE_get_config(struct AdapterControlBlock *pACB)
3235{
Ching Huang23509022017-12-05 09:35:34 +08003236 struct MessageUnit_E __iomem *reg = pACB->pmuE;
Ching Huang22c4ae52017-12-12 18:50:51 +08003237 uint32_t intmask_org;
Ching Huang23509022017-12-05 09:35:34 +08003238
3239 /* disable all outbound interrupt */
3240 intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
3241 writel(intmask_org | ARCMSR_HBEMU_ALL_INTMASKENABLE, &reg->host_int_mask);
3242 /* wait firmware ready */
Ching Huang22c4ae52017-12-12 18:50:51 +08003243 arcmsr_wait_firmware_ready(pACB);
Ching Huang23509022017-12-05 09:35:34 +08003244 mdelay(20);
3245 /* post "get config" instruction */
3246 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
3247
3248 pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3249 writel(pACB->out_doorbell, &reg->iobound_doorbell);
3250 /* wait message ready */
Ching Huang22c4ae52017-12-12 18:50:51 +08003251 if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
Ching Huang23509022017-12-05 09:35:34 +08003252 pr_notice("arcmsr%d: wait get adapter firmware "
3253 "miscellaneous data timeout\n", pACB->host->host_no);
3254 return false;
3255 }
Ching Huang1e9c8102017-12-12 18:53:33 +08003256 arcmsr_get_adapter_config(pACB, reg->msgcode_rwbuffer);
Ching Huang23509022017-12-05 09:35:34 +08003257 return true;
3258}
3259
Nick Chengae52e7f2010-06-18 15:39:12 +08003260static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08003261{
Ching Huang3df824a2014-08-19 14:29:41 +08003262 bool rtn = false;
3263
3264 switch (acb->adapter_type) {
3265 case ACB_ADAPTER_TYPE_A:
Ching Huang626fa322014-08-19 15:10:12 +08003266 rtn = arcmsr_hbaA_get_config(acb);
Ching Huang3df824a2014-08-19 14:29:41 +08003267 break;
3268 case ACB_ADAPTER_TYPE_B:
Ching Huang626fa322014-08-19 15:10:12 +08003269 rtn = arcmsr_hbaB_get_config(acb);
Ching Huang3df824a2014-08-19 14:29:41 +08003270 break;
3271 case ACB_ADAPTER_TYPE_C:
Ching Huang626fa322014-08-19 15:10:12 +08003272 rtn = arcmsr_hbaC_get_config(acb);
Ching Huang3df824a2014-08-19 14:29:41 +08003273 break;
Ching Huang5b374792014-08-19 15:25:22 +08003274 case ACB_ADAPTER_TYPE_D:
3275 rtn = arcmsr_hbaD_get_config(acb);
3276 break;
Ching Huang23509022017-12-05 09:35:34 +08003277 case ACB_ADAPTER_TYPE_E:
3278 rtn = arcmsr_hbaE_get_config(acb);
3279 break;
Ching Huang3df824a2014-08-19 14:29:41 +08003280 default:
3281 break;
3282 }
Ching Huangdd6206e2017-12-05 09:47:44 +08003283 acb->maxOutstanding = acb->firm_numbers_queue - 1;
3284 if (acb->host->can_queue >= acb->firm_numbers_queue)
3285 acb->host->can_queue = acb->maxOutstanding;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003286 else
Ching Huangdd6206e2017-12-05 09:47:44 +08003287 acb->maxOutstanding = acb->host->can_queue;
Ching Huangd076e4a2017-12-05 09:44:23 +08003288 acb->maxFreeCCB = acb->host->can_queue;
3289 if (acb->maxFreeCCB < ARCMSR_MAX_FREECCB_NUM)
3290 acb->maxFreeCCB += 64;
Ching Huang3df824a2014-08-19 14:29:41 +08003291 return rtn;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003292}
3293
Ching Huang626fa322014-08-19 15:10:12 +08003294static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07003295 struct CommandControlBlock *poll_ccb)
3296{
Al Viro80da1ad2007-10-29 05:08:28 +00003297 struct MessageUnit_A __iomem *reg = acb->pmuA;
Erich Chen1c57e862006-07-12 08:59:32 -07003298 struct CommandControlBlock *ccb;
Nick Chengae52e7f2010-06-18 15:39:12 +08003299 struct ARCMSR_CDB *arcmsr_cdb;
Erich Chen1c57e862006-07-12 08:59:32 -07003300 uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08003301 int rtn;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003302 bool error;
Ching Huang9e386a52018-12-19 16:43:15 +08003303 unsigned long ccb_cdb_phy;
3304
3305polling_hba_ccb_retry:
Erich Chen1c57e862006-07-12 08:59:32 -07003306 poll_count++;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003307 outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
Erich Chen1c57e862006-07-12 08:59:32 -07003308 writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
3309 while (1) {
3310 if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08003311 if (poll_ccb_done){
Nick Chengae52e7f2010-06-18 15:39:12 +08003312 rtn = SUCCESS;
Erich Chen1c57e862006-07-12 08:59:32 -07003313 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003314 }else {
3315 msleep(25);
3316 if (poll_count > 100){
Nick Chengae52e7f2010-06-18 15:39:12 +08003317 rtn = FAILED;
Erich Chen1c57e862006-07-12 08:59:32 -07003318 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08003319 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08003320 goto polling_hba_ccb_retry;
Erich Chen1c57e862006-07-12 08:59:32 -07003321 }
3322 }
Ching Huang9e386a52018-12-19 16:43:15 +08003323 ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
3324 if (acb->cdb_phyadd_hipart)
3325 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
3326 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengae52e7f2010-06-18 15:39:12 +08003327 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Ching Huangcab5aec2014-08-19 14:47:16 +08003328 poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003329 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
3330 if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
3331 printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
Erich Chen1c57e862006-07-12 08:59:32 -07003332 " poll command abort successfully \n"
3333 , acb->host->host_no
3334 , ccb->pcmd->device->id
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003335 , (u32)ccb->pcmd->device->lun
Erich Chen1c57e862006-07-12 08:59:32 -07003336 , ccb);
3337 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08003338 arcmsr_ccb_complete(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07003339 continue;
3340 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08003341 printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
3342 " command done ccb = '0x%p'"
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003343 "ccboutstandingcount = %d \n"
Erich Chen1c57e862006-07-12 08:59:32 -07003344 , acb->host->host_no
3345 , ccb
3346 , atomic_read(&acb->ccboutstandingcount));
3347 continue;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003348 }
3349 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
3350 arcmsr_report_ccb_state(acb, ccb, error);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003351 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003352 return rtn;
3353}
Nick Cheng1a4f5502007-09-13 17:26:40 +08003354
Ching Huang626fa322014-08-19 15:10:12 +08003355static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08003356 struct CommandControlBlock *poll_ccb)
3357{
Nick Chengcdd3cb12010-07-13 20:03:04 +08003358 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08003359 struct ARCMSR_CDB *arcmsr_cdb;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003360 struct CommandControlBlock *ccb;
3361 uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08003362 int index, rtn;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003363 bool error;
Ching Huange66764f2018-12-19 16:45:46 +08003364 unsigned long ccb_cdb_phy;
NickCheng97b99122011-01-06 17:32:41 +08003365
Ching Huange66764f2018-12-19 16:45:46 +08003366polling_hbb_ccb_retry:
Nick Chengcdd3cb12010-07-13 20:03:04 +08003367 poll_count++;
3368 /* clear doorbell interrupt */
Nick Chengae52e7f2010-06-18 15:39:12 +08003369 writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003370 while(1){
3371 index = reg->doneq_index;
Ching Huangc10b1d52014-08-19 15:20:31 +08003372 flag_ccb = reg->done_qbuffer[index];
3373 if (flag_ccb == 0) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08003374 if (poll_ccb_done){
Nick Chengae52e7f2010-06-18 15:39:12 +08003375 rtn = SUCCESS;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003376 break;
3377 }else {
3378 msleep(25);
3379 if (poll_count > 100){
Nick Chengae52e7f2010-06-18 15:39:12 +08003380 rtn = FAILED;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003381 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08003382 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08003383 goto polling_hbb_ccb_retry;
Erich Chen1c57e862006-07-12 08:59:32 -07003384 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08003385 }
Ching Huangc10b1d52014-08-19 15:20:31 +08003386 reg->done_qbuffer[index] = 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003387 index++;
3388 /*if last index number set it to 0 */
3389 index %= ARCMSR_MAX_HBB_POSTQUEUE;
3390 reg->doneq_index = index;
3391 /* check if command done with no error*/
Ching Huange66764f2018-12-19 16:45:46 +08003392 ccb_cdb_phy = (flag_ccb << 5) & 0xffffffff;
3393 if (acb->cdb_phyadd_hipart)
3394 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
3395 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengae52e7f2010-06-18 15:39:12 +08003396 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Ching Huangcab5aec2014-08-19 14:47:16 +08003397 poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003398 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
3399 if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
Nick Chengae52e7f2010-06-18 15:39:12 +08003400 printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
3401 " poll command abort successfully \n"
Nick Chengcdd3cb12010-07-13 20:03:04 +08003402 ,acb->host->host_no
3403 ,ccb->pcmd->device->id
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003404 ,(u32)ccb->pcmd->device->lun
Nick Chengcdd3cb12010-07-13 20:03:04 +08003405 ,ccb);
3406 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08003407 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003408 continue;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003409 }
3410 printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
3411 " command done ccb = '0x%p'"
3412 "ccboutstandingcount = %d \n"
3413 , acb->host->host_no
3414 , ccb
3415 , atomic_read(&acb->ccboutstandingcount));
3416 continue;
3417 }
3418 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
3419 arcmsr_report_ccb_state(acb, ccb, error);
3420 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003421 return rtn;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003422}
3423
Ching Huang626fa322014-08-19 15:10:12 +08003424static int arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb,
3425 struct CommandControlBlock *poll_ccb)
Nick Chengcdd3cb12010-07-13 20:03:04 +08003426{
Ching Huangc10b1d52014-08-19 15:20:31 +08003427 struct MessageUnit_C __iomem *reg = acb->pmuC;
Ching Huangc71ec552018-12-19 16:48:16 +08003428 uint32_t flag_ccb;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003429 struct ARCMSR_CDB *arcmsr_cdb;
3430 bool error;
3431 struct CommandControlBlock *pCCB;
3432 uint32_t poll_ccb_done = 0, poll_count = 0;
3433 int rtn;
Ching Huangc71ec552018-12-19 16:48:16 +08003434 unsigned long ccb_cdb_phy;
3435
Nick Chengcdd3cb12010-07-13 20:03:04 +08003436polling_hbc_ccb_retry:
3437 poll_count++;
3438 while (1) {
3439 if ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
3440 if (poll_ccb_done) {
3441 rtn = SUCCESS;
3442 break;
3443 } else {
3444 msleep(25);
3445 if (poll_count > 100) {
3446 rtn = FAILED;
3447 break;
3448 }
3449 goto polling_hbc_ccb_retry;
3450 }
3451 }
3452 flag_ccb = readl(&reg->outbound_queueport_low);
3453 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
Ching Huangc71ec552018-12-19 16:48:16 +08003454 if (acb->cdb_phyadd_hipart)
3455 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
3456 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003457 pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Ching Huangcab5aec2014-08-19 14:47:16 +08003458 poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003459 /* check ifcommand done with no error*/
3460 if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
3461 if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
3462 printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
3463 " poll command abort successfully \n"
3464 , acb->host->host_no
3465 , pCCB->pcmd->device->id
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003466 , (u32)pCCB->pcmd->device->lun
Nick Chengcdd3cb12010-07-13 20:03:04 +08003467 , pCCB);
Colin Ian King9b44ffa2019-11-14 18:00:07 +00003468 pCCB->pcmd->result = DID_ABORT << 16;
3469 arcmsr_ccb_complete(pCCB);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003470 continue;
3471 }
3472 printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
3473 " command done ccb = '0x%p'"
3474 "ccboutstandingcount = %d \n"
3475 , acb->host->host_no
3476 , pCCB
3477 , atomic_read(&acb->ccboutstandingcount));
3478 continue;
3479 }
3480 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
3481 arcmsr_report_ccb_state(acb, pCCB, error);
3482 }
3483 return rtn;
3484}
Ching Huang5b374792014-08-19 15:25:22 +08003485
3486static int arcmsr_hbaD_polling_ccbdone(struct AdapterControlBlock *acb,
3487 struct CommandControlBlock *poll_ccb)
3488{
3489 bool error;
Ching Huanga36ade42018-12-19 16:51:14 +08003490 uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb;
Ching Huang3b8155d2014-09-15 19:05:33 +08003491 int rtn, doneq_index, index_stripped, outbound_write_pointer, toggle;
Lee Jones18bc4352020-07-13 08:46:30 +01003492 unsigned long flags, ccb_cdb_phy;
Ching Huang5b374792014-08-19 15:25:22 +08003493 struct ARCMSR_CDB *arcmsr_cdb;
3494 struct CommandControlBlock *pCCB;
3495 struct MessageUnit_D *pmu = acb->pmuD;
3496
3497polling_hbaD_ccb_retry:
3498 poll_count++;
3499 while (1) {
Ching Huang3b8155d2014-09-15 19:05:33 +08003500 spin_lock_irqsave(&acb->doneq_lock, flags);
Ching Huang5b374792014-08-19 15:25:22 +08003501 outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
3502 doneq_index = pmu->doneq_index;
3503 if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
Ching Huang3b8155d2014-09-15 19:05:33 +08003504 spin_unlock_irqrestore(&acb->doneq_lock, flags);
Ching Huang5b374792014-08-19 15:25:22 +08003505 if (poll_ccb_done) {
3506 rtn = SUCCESS;
3507 break;
3508 } else {
3509 msleep(25);
3510 if (poll_count > 40) {
3511 rtn = FAILED;
3512 break;
3513 }
3514 goto polling_hbaD_ccb_retry;
3515 }
3516 }
Ching Huang3b8155d2014-09-15 19:05:33 +08003517 toggle = doneq_index & 0x4000;
3518 index_stripped = (doneq_index & 0xFFF) + 1;
3519 index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
3520 pmu->doneq_index = index_stripped ? (index_stripped | toggle) :
3521 ((toggle ^ 0x4000) + 1);
Ching Huang5b374792014-08-19 15:25:22 +08003522 doneq_index = pmu->doneq_index;
Ching Huang3b8155d2014-09-15 19:05:33 +08003523 spin_unlock_irqrestore(&acb->doneq_lock, flags);
Ching Huang5b374792014-08-19 15:25:22 +08003524 flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
3525 ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
Ching Huanga36ade42018-12-19 16:51:14 +08003526 if (acb->cdb_phyadd_hipart)
3527 ccb_cdb_phy = ccb_cdb_phy | acb->cdb_phyadd_hipart;
Ching Huang5b374792014-08-19 15:25:22 +08003528 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
3529 ccb_cdb_phy);
3530 pCCB = container_of(arcmsr_cdb, struct CommandControlBlock,
3531 arcmsr_cdb);
3532 poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0;
3533 if ((pCCB->acb != acb) ||
3534 (pCCB->startdone != ARCMSR_CCB_START)) {
3535 if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
3536 pr_notice("arcmsr%d: scsi id = %d "
3537 "lun = %d ccb = '0x%p' poll command "
3538 "abort successfully\n"
3539 , acb->host->host_no
3540 , pCCB->pcmd->device->id
3541 , (u32)pCCB->pcmd->device->lun
3542 , pCCB);
3543 pCCB->pcmd->result = DID_ABORT << 16;
3544 arcmsr_ccb_complete(pCCB);
3545 continue;
3546 }
3547 pr_notice("arcmsr%d: polling an illegal "
3548 "ccb command done ccb = '0x%p' "
3549 "ccboutstandingcount = %d\n"
3550 , acb->host->host_no
3551 , pCCB
3552 , atomic_read(&acb->ccboutstandingcount));
3553 continue;
3554 }
3555 error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
3556 ? true : false;
3557 arcmsr_report_ccb_state(acb, pCCB, error);
3558 }
3559 return rtn;
3560}
3561
Ching Huang23509022017-12-05 09:35:34 +08003562static int arcmsr_hbaE_polling_ccbdone(struct AdapterControlBlock *acb,
3563 struct CommandControlBlock *poll_ccb)
3564{
3565 bool error;
3566 uint32_t poll_ccb_done = 0, poll_count = 0, doneq_index;
3567 uint16_t cmdSMID;
3568 unsigned long flags;
3569 int rtn;
3570 struct CommandControlBlock *pCCB;
3571 struct MessageUnit_E __iomem *reg = acb->pmuE;
3572
3573 polling_hbaC_ccb_retry:
3574 poll_count++;
3575 while (1) {
3576 spin_lock_irqsave(&acb->doneq_lock, flags);
3577 doneq_index = acb->doneq_index;
3578 if ((readl(&reg->reply_post_producer_index) & 0xFFFF) ==
3579 doneq_index) {
3580 spin_unlock_irqrestore(&acb->doneq_lock, flags);
3581 if (poll_ccb_done) {
3582 rtn = SUCCESS;
3583 break;
3584 } else {
3585 msleep(25);
3586 if (poll_count > 40) {
3587 rtn = FAILED;
3588 break;
3589 }
3590 goto polling_hbaC_ccb_retry;
3591 }
3592 }
3593 cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
3594 doneq_index++;
3595 if (doneq_index >= acb->completionQ_entry)
3596 doneq_index = 0;
3597 acb->doneq_index = doneq_index;
3598 spin_unlock_irqrestore(&acb->doneq_lock, flags);
3599 pCCB = acb->pccb_pool[cmdSMID];
3600 poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0;
3601 /* check if command done with no error*/
3602 if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
3603 if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
3604 pr_notice("arcmsr%d: scsi id = %d "
3605 "lun = %d ccb = '0x%p' poll command "
3606 "abort successfully\n"
3607 , acb->host->host_no
3608 , pCCB->pcmd->device->id
3609 , (u32)pCCB->pcmd->device->lun
3610 , pCCB);
3611 pCCB->pcmd->result = DID_ABORT << 16;
3612 arcmsr_ccb_complete(pCCB);
3613 continue;
3614 }
3615 pr_notice("arcmsr%d: polling an illegal "
3616 "ccb command done ccb = '0x%p' "
3617 "ccboutstandingcount = %d\n"
3618 , acb->host->host_no
3619 , pCCB
3620 , atomic_read(&acb->ccboutstandingcount));
3621 continue;
3622 }
3623 error = (acb->pCompletionQ[doneq_index].cmdFlag &
3624 ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
3625 arcmsr_report_ccb_state(acb, pCCB, error);
3626 }
3627 writel(doneq_index, &reg->reply_post_consumer_index);
3628 return rtn;
3629}
3630
Nick Chengae52e7f2010-06-18 15:39:12 +08003631static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08003632 struct CommandControlBlock *poll_ccb)
3633{
Nick Chengae52e7f2010-06-18 15:39:12 +08003634 int rtn = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003635 switch (acb->adapter_type) {
3636
3637 case ACB_ADAPTER_TYPE_A: {
Ching Huang626fa322014-08-19 15:10:12 +08003638 rtn = arcmsr_hbaA_polling_ccbdone(acb, poll_ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003639 }
3640 break;
3641
3642 case ACB_ADAPTER_TYPE_B: {
Ching Huang626fa322014-08-19 15:10:12 +08003643 rtn = arcmsr_hbaB_polling_ccbdone(acb, poll_ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07003644 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08003645 break;
3646 case ACB_ADAPTER_TYPE_C: {
Ching Huang626fa322014-08-19 15:10:12 +08003647 rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003648 }
Ching Huang5b374792014-08-19 15:25:22 +08003649 break;
3650 case ACB_ADAPTER_TYPE_D:
3651 rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
3652 break;
Ching Huang23509022017-12-05 09:35:34 +08003653 case ACB_ADAPTER_TYPE_E:
3654 rtn = arcmsr_hbaE_polling_ccbdone(acb, poll_ccb);
3655 break;
Erich Chen1c57e862006-07-12 08:59:32 -07003656 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003657 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07003658}
Nick Cheng1a4f5502007-09-13 17:26:40 +08003659
Ching Huangb416c092017-12-05 09:59:52 +08003660static void arcmsr_set_iop_datetime(struct timer_list *t)
3661{
3662 struct AdapterControlBlock *pacb = from_timer(pacb, t, refresh_timer);
Arnd Bergmann45596c72018-01-22 00:12:26 +01003663 unsigned int next_time;
3664 struct tm tm;
3665
Ching Huangb416c092017-12-05 09:59:52 +08003666 union {
3667 struct {
3668 uint16_t signature;
3669 uint8_t year;
3670 uint8_t month;
3671 uint8_t date;
3672 uint8_t hour;
3673 uint8_t minute;
3674 uint8_t second;
3675 } a;
3676 struct {
3677 uint32_t msg_time[2];
3678 } b;
3679 } datetime;
3680
Arnd Bergmann45596c72018-01-22 00:12:26 +01003681 time64_to_tm(ktime_get_real_seconds(), -sys_tz.tz_minuteswest * 60, &tm);
Ching Huangb416c092017-12-05 09:59:52 +08003682
3683 datetime.a.signature = 0x55AA;
Arnd Bergmann45596c72018-01-22 00:12:26 +01003684 datetime.a.year = tm.tm_year - 100; /* base 2000 instead of 1900 */
3685 datetime.a.month = tm.tm_mon;
3686 datetime.a.date = tm.tm_mday;
3687 datetime.a.hour = tm.tm_hour;
3688 datetime.a.minute = tm.tm_min;
3689 datetime.a.second = tm.tm_sec;
Ching Huangb416c092017-12-05 09:59:52 +08003690
3691 switch (pacb->adapter_type) {
3692 case ACB_ADAPTER_TYPE_A: {
3693 struct MessageUnit_A __iomem *reg = pacb->pmuA;
3694 writel(datetime.b.msg_time[0], &reg->message_rwbuffer[0]);
3695 writel(datetime.b.msg_time[1], &reg->message_rwbuffer[1]);
3696 writel(ARCMSR_INBOUND_MESG0_SYNC_TIMER, &reg->inbound_msgaddr0);
3697 break;
3698 }
3699 case ACB_ADAPTER_TYPE_B: {
3700 uint32_t __iomem *rwbuffer;
3701 struct MessageUnit_B *reg = pacb->pmuB;
3702 rwbuffer = reg->message_rwbuffer;
3703 writel(datetime.b.msg_time[0], rwbuffer++);
3704 writel(datetime.b.msg_time[1], rwbuffer++);
3705 writel(ARCMSR_MESSAGE_SYNC_TIMER, reg->drv2iop_doorbell);
3706 break;
3707 }
3708 case ACB_ADAPTER_TYPE_C: {
3709 struct MessageUnit_C __iomem *reg = pacb->pmuC;
3710 writel(datetime.b.msg_time[0], &reg->msgcode_rwbuffer[0]);
3711 writel(datetime.b.msg_time[1], &reg->msgcode_rwbuffer[1]);
3712 writel(ARCMSR_INBOUND_MESG0_SYNC_TIMER, &reg->inbound_msgaddr0);
3713 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
3714 break;
3715 }
3716 case ACB_ADAPTER_TYPE_D: {
3717 uint32_t __iomem *rwbuffer;
3718 struct MessageUnit_D *reg = pacb->pmuD;
3719 rwbuffer = reg->msgcode_rwbuffer;
3720 writel(datetime.b.msg_time[0], rwbuffer++);
3721 writel(datetime.b.msg_time[1], rwbuffer++);
3722 writel(ARCMSR_INBOUND_MESG0_SYNC_TIMER, reg->inbound_msgaddr0);
3723 break;
3724 }
3725 case ACB_ADAPTER_TYPE_E: {
3726 struct MessageUnit_E __iomem *reg = pacb->pmuE;
3727 writel(datetime.b.msg_time[0], &reg->msgcode_rwbuffer[0]);
3728 writel(datetime.b.msg_time[1], &reg->msgcode_rwbuffer[1]);
3729 writel(ARCMSR_INBOUND_MESG0_SYNC_TIMER, &reg->inbound_msgaddr0);
3730 pacb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3731 writel(pacb->out_doorbell, &reg->iobound_doorbell);
3732 break;
3733 }
3734 }
3735 if (sys_tz.tz_minuteswest)
3736 next_time = ARCMSR_HOURS;
3737 else
3738 next_time = ARCMSR_MINUTES;
3739 mod_timer(&pacb->refresh_timer, jiffies + msecs_to_jiffies(next_time));
3740}
3741
Nick Cheng1a4f5502007-09-13 17:26:40 +08003742static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003743{
Nick Chengae52e7f2010-06-18 15:39:12 +08003744 uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
Ching Huang6e38adf2014-08-19 15:14:14 +08003745 dma_addr_t dma_coherent_handle;
Dan Carpentere2c70422014-02-11 19:06:33 +03003746
Nick Cheng1a4f5502007-09-13 17:26:40 +08003747 /*
3748 ********************************************************************
3749 ** here we need to tell iop 331 our freeccb.HighPart
3750 ** if freeccb.HighPart is not zero
3751 ********************************************************************
3752 */
Ching Huang6e38adf2014-08-19 15:14:14 +08003753 switch (acb->adapter_type) {
3754 case ACB_ADAPTER_TYPE_B:
Ching Huang5b374792014-08-19 15:25:22 +08003755 case ACB_ADAPTER_TYPE_D:
Ching Huang6e38adf2014-08-19 15:14:14 +08003756 dma_coherent_handle = acb->dma_coherent_handle2;
3757 break;
Ching Huang23509022017-12-05 09:35:34 +08003758 case ACB_ADAPTER_TYPE_E:
3759 dma_coherent_handle = acb->dma_coherent_handle +
3760 offsetof(struct CommandControlBlock, arcmsr_cdb);
3761 break;
Ching Huang6e38adf2014-08-19 15:14:14 +08003762 default:
3763 dma_coherent_handle = acb->dma_coherent_handle;
3764 break;
3765 }
3766 cdb_phyaddr = lower_32_bits(dma_coherent_handle);
3767 cdb_phyaddr_hi32 = upper_32_bits(dma_coherent_handle);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003768 acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
Ching Huang7860a482018-12-19 16:34:58 +08003769 acb->cdb_phyadd_hipart = ((uint64_t)cdb_phyaddr_hi32) << 32;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003770 /*
3771 ***********************************************************************
3772 ** if adapter type B, set window of "post command Q"
3773 ***********************************************************************
3774 */
3775 switch (acb->adapter_type) {
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003776
Nick Cheng1a4f5502007-09-13 17:26:40 +08003777 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +08003778 if (cdb_phyaddr_hi32 != 0) {
Al Viro80da1ad2007-10-29 05:08:28 +00003779 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003780 writel(ARCMSR_SIGNATURE_SET_CONFIG, \
3781 &reg->message_rwbuffer[0]);
Nick Chengae52e7f2010-06-18 15:39:12 +08003782 writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003783 writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
3784 &reg->inbound_msgaddr0);
Ching Huang626fa322014-08-19 15:10:12 +08003785 if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08003786 printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
3787 part physical address timeout\n",
3788 acb->host->host_no);
3789 return 1;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003790 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08003791 }
3792 }
3793 break;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003794
Nick Cheng1a4f5502007-09-13 17:26:40 +08003795 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00003796 uint32_t __iomem *rwbuffer;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003797
Al Viro80da1ad2007-10-29 05:08:28 +00003798 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003799 reg->postq_index = 0;
3800 reg->doneq_index = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08003801 writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08003802 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nik Nyby47268a42015-06-30 17:25:27 -04003803 printk(KERN_NOTICE "arcmsr%d: cannot set driver mode\n", \
Nick Cheng1a4f5502007-09-13 17:26:40 +08003804 acb->host->host_no);
3805 return 1;
3806 }
Nick Chengae52e7f2010-06-18 15:39:12 +08003807 rwbuffer = reg->message_rwbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003808 /* driver "set config" signature */
3809 writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
3810 /* normal should be zero */
Nick Chengae52e7f2010-06-18 15:39:12 +08003811 writel(cdb_phyaddr_hi32, rwbuffer++);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003812 /* postQ size (256 + 8)*4 */
Ching Huang6e38adf2014-08-19 15:14:14 +08003813 writel(cdb_phyaddr, rwbuffer++);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003814 /* doneQ size (256 + 8)*4 */
Ching Huang6e38adf2014-08-19 15:14:14 +08003815 writel(cdb_phyaddr + 1056, rwbuffer++);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003816 /* ccb maxQ size must be --> [(256 + 8)*4]*/
3817 writel(1056, rwbuffer);
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003818
Nick Chengae52e7f2010-06-18 15:39:12 +08003819 writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08003820 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08003821 printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
3822 timeout \n",acb->host->host_no);
3823 return 1;
3824 }
Ching Huanga5849722014-08-19 15:01:28 +08003825 writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08003826 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Ching Huanga5849722014-08-19 15:01:28 +08003827 pr_err("arcmsr%d: can't set driver mode.\n",
3828 acb->host->host_no);
3829 return 1;
3830 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08003831 }
3832 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003833 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08003834 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003835
Tomas Henzl8b7eb862011-04-29 16:28:24 +02003836 printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n",
3837 acb->adapter_index, cdb_phyaddr_hi32);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003838 writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
3839 writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[1]);
3840 writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
3841 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08003842 if (!arcmsr_hbaC_wait_msgint_ready(acb)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08003843 printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
3844 timeout \n", acb->host->host_no);
3845 return 1;
3846 }
3847 }
Ching Huang5b374792014-08-19 15:25:22 +08003848 break;
3849 case ACB_ADAPTER_TYPE_D: {
3850 uint32_t __iomem *rwbuffer;
3851 struct MessageUnit_D *reg = acb->pmuD;
3852 reg->postq_index = 0;
3853 reg->doneq_index = 0;
3854 rwbuffer = reg->msgcode_rwbuffer;
3855 writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
3856 writel(cdb_phyaddr_hi32, rwbuffer++);
3857 writel(cdb_phyaddr, rwbuffer++);
3858 writel(cdb_phyaddr + (ARCMSR_MAX_ARC1214_POSTQUEUE *
3859 sizeof(struct InBound_SRB)), rwbuffer++);
3860 writel(0x100, rwbuffer);
3861 writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, reg->inbound_msgaddr0);
3862 if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
3863 pr_notice("arcmsr%d: 'set command Q window' timeout\n",
3864 acb->host->host_no);
3865 return 1;
3866 }
3867 }
3868 break;
Ching Huang23509022017-12-05 09:35:34 +08003869 case ACB_ADAPTER_TYPE_E: {
3870 struct MessageUnit_E __iomem *reg = acb->pmuE;
3871 writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
3872 writel(ARCMSR_SIGNATURE_1884, &reg->msgcode_rwbuffer[1]);
3873 writel(cdb_phyaddr, &reg->msgcode_rwbuffer[2]);
3874 writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[3]);
3875 writel(acb->ccbsize, &reg->msgcode_rwbuffer[4]);
3876 dma_coherent_handle = acb->dma_coherent_handle2;
3877 cdb_phyaddr = (uint32_t)(dma_coherent_handle & 0xffffffff);
3878 cdb_phyaddr_hi32 = (uint32_t)((dma_coherent_handle >> 16) >> 16);
3879 writel(cdb_phyaddr, &reg->msgcode_rwbuffer[5]);
3880 writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[6]);
Ching Huang381d66d2018-12-19 16:24:03 +08003881 writel(acb->ioqueue_size, &reg->msgcode_rwbuffer[7]);
Ching Huang23509022017-12-05 09:35:34 +08003882 writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
3883 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3884 writel(acb->out_doorbell, &reg->iobound_doorbell);
3885 if (!arcmsr_hbaE_wait_msgint_ready(acb)) {
3886 pr_notice("arcmsr%d: 'set command Q window' timeout \n",
3887 acb->host->host_no);
3888 return 1;
3889 }
3890 }
3891 break;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003892 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08003893 return 0;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08003894}
3895
Nick Cheng1a4f5502007-09-13 17:26:40 +08003896static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
3897{
3898 uint32_t firmware_state = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003899 switch (acb->adapter_type) {
3900
3901 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00003902 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003903 do {
Ching Huangc2c62eb2018-03-15 14:37:40 +08003904 if (!(acb->acb_flags & ACB_F_IOP_INITED))
3905 msleep(20);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003906 firmware_state = readl(&reg->outbound_msgaddr1);
3907 } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
3908 }
3909 break;
3910
3911 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00003912 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003913 do {
Ching Huangc2c62eb2018-03-15 14:37:40 +08003914 if (!(acb->acb_flags & ACB_F_IOP_INITED))
3915 msleep(20);
Nick Chengae52e7f2010-06-18 15:39:12 +08003916 firmware_state = readl(reg->iop2drv_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003917 } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
Nick Chengae52e7f2010-06-18 15:39:12 +08003918 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08003919 }
3920 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003921 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08003922 struct MessageUnit_C __iomem *reg = acb->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08003923 do {
Ching Huangc2c62eb2018-03-15 14:37:40 +08003924 if (!(acb->acb_flags & ACB_F_IOP_INITED))
3925 msleep(20);
Nick Chengcdd3cb12010-07-13 20:03:04 +08003926 firmware_state = readl(&reg->outbound_msgaddr1);
3927 } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
3928 }
Ching Huang5b374792014-08-19 15:25:22 +08003929 break;
3930 case ACB_ADAPTER_TYPE_D: {
3931 struct MessageUnit_D *reg = acb->pmuD;
3932 do {
Ching Huangc2c62eb2018-03-15 14:37:40 +08003933 if (!(acb->acb_flags & ACB_F_IOP_INITED))
3934 msleep(20);
Ching Huang5b374792014-08-19 15:25:22 +08003935 firmware_state = readl(reg->outbound_msgaddr1);
3936 } while ((firmware_state &
3937 ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
3938 }
3939 break;
Ching Huang23509022017-12-05 09:35:34 +08003940 case ACB_ADAPTER_TYPE_E: {
3941 struct MessageUnit_E __iomem *reg = acb->pmuE;
3942 do {
Ching Huangc2c62eb2018-03-15 14:37:40 +08003943 if (!(acb->acb_flags & ACB_F_IOP_INITED))
3944 msleep(20);
Ching Huang23509022017-12-05 09:35:34 +08003945 firmware_state = readl(&reg->outbound_msgaddr1);
3946 } while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0);
3947 }
3948 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08003949 }
3950}
3951
Kees Cooke99e88a2017-10-16 14:43:17 -07003952static void arcmsr_request_device_map(struct timer_list *t)
Nick Cheng36b83de2010-05-17 11:22:42 +08003953{
Kees Cooke99e88a2017-10-16 14:43:17 -07003954 struct AdapterControlBlock *acb = from_timer(acb, t, eternal_timer);
Ching Huang6ae9abe2017-12-13 16:33:36 +08003955 if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
3956 (acb->acb_flags & ACB_F_BUS_RESET) ||
3957 (acb->acb_flags & ACB_F_ABORT)) {
3958 mod_timer(&acb->eternal_timer,
3959 jiffies + msecs_to_jiffies(6 * HZ));
3960 } else {
3961 acb->fw_flag = FW_NORMAL;
3962 if (atomic_read(&acb->ante_token_value) ==
3963 atomic_read(&acb->rq_map_token)) {
3964 atomic_set(&acb->rq_map_token, 16);
3965 }
3966 atomic_set(&acb->ante_token_value,
3967 atomic_read(&acb->rq_map_token));
3968 if (atomic_dec_and_test(&acb->rq_map_token)) {
3969 mod_timer(&acb->eternal_timer, jiffies +
3970 msecs_to_jiffies(6 * HZ));
3971 return;
3972 }
3973 switch (acb->adapter_type) {
Nick Cheng36b83de2010-05-17 11:22:42 +08003974 case ACB_ADAPTER_TYPE_A: {
Ching Huang6ae9abe2017-12-13 16:33:36 +08003975 struct MessageUnit_A __iomem *reg = acb->pmuA;
3976 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
3977 break;
3978 }
Nick Cheng36b83de2010-05-17 11:22:42 +08003979 case ACB_ADAPTER_TYPE_B: {
Ching Huang6ae9abe2017-12-13 16:33:36 +08003980 struct MessageUnit_B *reg = acb->pmuB;
3981 writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
3982 break;
3983 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08003984 case ACB_ADAPTER_TYPE_C: {
Ching Huang6ae9abe2017-12-13 16:33:36 +08003985 struct MessageUnit_C __iomem *reg = acb->pmuC;
3986 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
3987 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
3988 break;
3989 }
3990 case ACB_ADAPTER_TYPE_D: {
3991 struct MessageUnit_D *reg = acb->pmuD;
3992 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, reg->inbound_msgaddr0);
3993 break;
3994 }
3995 case ACB_ADAPTER_TYPE_E: {
3996 struct MessageUnit_E __iomem *reg = acb->pmuE;
3997 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
3998 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3999 writel(acb->out_doorbell, &reg->iobound_doorbell);
4000 break;
4001 }
4002 default:
4003 return;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004004 }
Ching Huang6ae9abe2017-12-13 16:33:36 +08004005 acb->acb_flags |= ACB_F_MSG_GET_CONFIG;
4006 mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
Nick Cheng36b83de2010-05-17 11:22:42 +08004007 }
4008}
4009
Ching Huang626fa322014-08-19 15:10:12 +08004010static void arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08004011{
Al Viro80da1ad2007-10-29 05:08:28 +00004012 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08004013 acb->acb_flags |= ACB_F_MSG_START_BGRB;
4014 writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
Ching Huang626fa322014-08-19 15:10:12 +08004015 if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08004016 printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02004017 rebuild' timeout \n", acb->host->host_no);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004018 }
4019}
4020
Ching Huang626fa322014-08-19 15:10:12 +08004021static void arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08004022{
Al Viro80da1ad2007-10-29 05:08:28 +00004023 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08004024 acb->acb_flags |= ACB_F_MSG_START_BGRB;
Nick Chengae52e7f2010-06-18 15:39:12 +08004025 writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08004026 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08004027 printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02004028 rebuild' timeout \n",acb->host->host_no);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004029 }
4030}
4031
Ching Huang626fa322014-08-19 15:10:12 +08004032static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB)
Nick Chengcdd3cb12010-07-13 20:03:04 +08004033{
Ching Huangc10b1d52014-08-19 15:20:31 +08004034 struct MessageUnit_C __iomem *phbcmu = pACB->pmuC;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004035 pACB->acb_flags |= ACB_F_MSG_START_BGRB;
4036 writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
4037 writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08004038 if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08004039 printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02004040 rebuild' timeout \n", pACB->host->host_no);
Nick Chengcdd3cb12010-07-13 20:03:04 +08004041 }
4042 return;
4043}
Ching Huang5b374792014-08-19 15:25:22 +08004044
4045static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB)
4046{
4047 struct MessageUnit_D *pmu = pACB->pmuD;
4048
4049 pACB->acb_flags |= ACB_F_MSG_START_BGRB;
4050 writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0);
4051 if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
4052 pr_notice("arcmsr%d: wait 'start adapter "
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02004053 "background rebuild' timeout\n", pACB->host->host_no);
Ching Huang5b374792014-08-19 15:25:22 +08004054 }
4055}
4056
Ching Huang23509022017-12-05 09:35:34 +08004057static void arcmsr_hbaE_start_bgrb(struct AdapterControlBlock *pACB)
4058{
4059 struct MessageUnit_E __iomem *pmu = pACB->pmuE;
4060
4061 pACB->acb_flags |= ACB_F_MSG_START_BGRB;
4062 writel(ARCMSR_INBOUND_MESG0_START_BGRB, &pmu->inbound_msgaddr0);
4063 pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
4064 writel(pACB->out_doorbell, &pmu->iobound_doorbell);
4065 if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
4066 pr_notice("arcmsr%d: wait 'start adapter "
Geert Uytterhoeven948dff7a2018-09-03 19:35:29 +02004067 "background rebuild' timeout \n", pACB->host->host_no);
Ching Huang23509022017-12-05 09:35:34 +08004068 }
4069}
4070
Nick Cheng1a4f5502007-09-13 17:26:40 +08004071static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
4072{
4073 switch (acb->adapter_type) {
4074 case ACB_ADAPTER_TYPE_A:
Ching Huang626fa322014-08-19 15:10:12 +08004075 arcmsr_hbaA_start_bgrb(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004076 break;
4077 case ACB_ADAPTER_TYPE_B:
Ching Huang626fa322014-08-19 15:10:12 +08004078 arcmsr_hbaB_start_bgrb(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004079 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004080 case ACB_ADAPTER_TYPE_C:
Ching Huang626fa322014-08-19 15:10:12 +08004081 arcmsr_hbaC_start_bgrb(acb);
Ching Huang5b374792014-08-19 15:25:22 +08004082 break;
4083 case ACB_ADAPTER_TYPE_D:
4084 arcmsr_hbaD_start_bgrb(acb);
4085 break;
Ching Huang23509022017-12-05 09:35:34 +08004086 case ACB_ADAPTER_TYPE_E:
4087 arcmsr_hbaE_start_bgrb(acb);
4088 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08004089 }
4090}
4091
4092static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
4093{
4094 switch (acb->adapter_type) {
4095 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00004096 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08004097 uint32_t outbound_doorbell;
4098 /* empty doorbell Qbuffer if door bell ringed */
4099 outbound_doorbell = readl(&reg->outbound_doorbell);
4100 /*clear doorbell interrupt */
4101 writel(outbound_doorbell, &reg->outbound_doorbell);
4102 writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
4103 }
4104 break;
4105
4106 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00004107 struct MessageUnit_B *reg = acb->pmuB;
Ching Huang2124c5b2017-12-05 10:02:16 +08004108 uint32_t outbound_doorbell, i;
4109 writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
Nick Chengae52e7f2010-06-18 15:39:12 +08004110 writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004111 /* let IOP know data has been read */
Ching Huang2124c5b2017-12-05 10:02:16 +08004112 for(i=0; i < 200; i++) {
4113 msleep(20);
4114 outbound_doorbell = readl(reg->iop2drv_doorbell);
4115 if( outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
4116 writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
4117 writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
4118 } else
4119 break;
4120 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08004121 }
4122 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004123 case ACB_ADAPTER_TYPE_C: {
Ching Huangc10b1d52014-08-19 15:20:31 +08004124 struct MessageUnit_C __iomem *reg = acb->pmuC;
Ching Huang5eb6bfa2014-08-19 15:07:35 +08004125 uint32_t outbound_doorbell, i;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004126 /* empty doorbell Qbuffer if door bell ringed */
4127 outbound_doorbell = readl(&reg->outbound_doorbell);
4128 writel(outbound_doorbell, &reg->outbound_doorbell_clear);
4129 writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
Ching Huang5eb6bfa2014-08-19 15:07:35 +08004130 for (i = 0; i < 200; i++) {
4131 msleep(20);
4132 outbound_doorbell = readl(&reg->outbound_doorbell);
4133 if (outbound_doorbell &
4134 ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
4135 writel(outbound_doorbell,
4136 &reg->outbound_doorbell_clear);
4137 writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK,
4138 &reg->inbound_doorbell);
4139 } else
4140 break;
4141 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08004142 }
Ching Huang5b374792014-08-19 15:25:22 +08004143 break;
4144 case ACB_ADAPTER_TYPE_D: {
4145 struct MessageUnit_D *reg = acb->pmuD;
4146 uint32_t outbound_doorbell, i;
4147 /* empty doorbell Qbuffer if door bell ringed */
4148 outbound_doorbell = readl(reg->outbound_doorbell);
4149 writel(outbound_doorbell, reg->outbound_doorbell);
4150 writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
4151 reg->inbound_doorbell);
4152 for (i = 0; i < 200; i++) {
4153 msleep(20);
4154 outbound_doorbell = readl(reg->outbound_doorbell);
4155 if (outbound_doorbell &
4156 ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK) {
4157 writel(outbound_doorbell,
4158 reg->outbound_doorbell);
4159 writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
4160 reg->inbound_doorbell);
4161 } else
4162 break;
4163 }
4164 }
4165 break;
Ching Huang23509022017-12-05 09:35:34 +08004166 case ACB_ADAPTER_TYPE_E: {
4167 struct MessageUnit_E __iomem *reg = acb->pmuE;
4168 uint32_t i, tmp;
4169
4170 acb->in_doorbell = readl(&reg->iobound_doorbell);
4171 writel(0, &reg->host_int_status); /*clear interrupt*/
4172 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
4173 writel(acb->out_doorbell, &reg->iobound_doorbell);
4174 for(i=0; i < 200; i++) {
4175 msleep(20);
4176 tmp = acb->in_doorbell;
4177 acb->in_doorbell = readl(&reg->iobound_doorbell);
4178 if((tmp ^ acb->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK) {
4179 writel(0, &reg->host_int_status); /*clear interrupt*/
4180 acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
4181 writel(acb->out_doorbell, &reg->iobound_doorbell);
4182 } else
4183 break;
4184 }
4185 }
4186 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08004187 }
4188}
Erich Chen1c57e862006-07-12 08:59:32 -07004189
Nick Cheng76d78302008-02-04 23:53:24 -08004190static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
4191{
4192 switch (acb->adapter_type) {
4193 case ACB_ADAPTER_TYPE_A:
4194 return;
4195 case ACB_ADAPTER_TYPE_B:
4196 {
4197 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08004198 writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
Ching Huang626fa322014-08-19 15:10:12 +08004199 if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
Nick Cheng76d78302008-02-04 23:53:24 -08004200 printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
4201 return;
4202 }
4203 }
4204 break;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004205 case ACB_ADAPTER_TYPE_C:
4206 return;
Nick Cheng76d78302008-02-04 23:53:24 -08004207 }
4208 return;
4209}
4210
Nick Cheng36b83de2010-05-17 11:22:42 +08004211static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
4212{
4213 uint8_t value[64];
Nick Chengcdd3cb12010-07-13 20:03:04 +08004214 int i, count = 0;
4215 struct MessageUnit_A __iomem *pmuA = acb->pmuA;
4216 struct MessageUnit_C __iomem *pmuC = acb->pmuC;
Ching Huang5b374792014-08-19 15:25:22 +08004217 struct MessageUnit_D *pmuD = acb->pmuD;
Dan Carpenter6ad819b2012-06-09 12:10:19 +03004218
Nick Cheng36b83de2010-05-17 11:22:42 +08004219 /* backup pci config data */
Nick Chengcdd3cb12010-07-13 20:03:04 +08004220 printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
Nick Cheng36b83de2010-05-17 11:22:42 +08004221 for (i = 0; i < 64; i++) {
4222 pci_read_config_byte(acb->pdev, i, &value[i]);
4223 }
4224 /* hardware reset signal */
Colin Ian Kingca2ade22018-10-01 00:03:07 +01004225 if (acb->dev_id == 0x1680) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08004226 writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
Colin Ian Kingca2ade22018-10-01 00:03:07 +01004227 } else if (acb->dev_id == 0x1880) {
Nick Chengcdd3cb12010-07-13 20:03:04 +08004228 do {
4229 count++;
4230 writel(0xF, &pmuC->write_sequence);
4231 writel(0x4, &pmuC->write_sequence);
4232 writel(0xB, &pmuC->write_sequence);
4233 writel(0x2, &pmuC->write_sequence);
4234 writel(0x7, &pmuC->write_sequence);
4235 writel(0xD, &pmuC->write_sequence);
Dan Carpenter6ad819b2012-06-09 12:10:19 +03004236 } while (((readl(&pmuC->host_diagnostic) & ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
Nick Chengcdd3cb12010-07-13 20:03:04 +08004237 writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
Ching Huang23509022017-12-05 09:35:34 +08004238 } else if (acb->dev_id == 0x1884) {
4239 struct MessageUnit_E __iomem *pmuE = acb->pmuE;
4240 do {
4241 count++;
4242 writel(0x4, &pmuE->write_sequence_3xxx);
4243 writel(0xB, &pmuE->write_sequence_3xxx);
4244 writel(0x2, &pmuE->write_sequence_3xxx);
4245 writel(0x7, &pmuE->write_sequence_3xxx);
4246 writel(0xD, &pmuE->write_sequence_3xxx);
4247 mdelay(10);
4248 } while (((readl(&pmuE->host_diagnostic_3xxx) &
4249 ARCMSR_ARC1884_DiagWrite_ENABLE) == 0) && (count < 5));
4250 writel(ARCMSR_ARC188X_RESET_ADAPTER, &pmuE->host_diagnostic_3xxx);
Colin Ian Kingca2ade22018-10-01 00:03:07 +01004251 } else if (acb->dev_id == 0x1214) {
Ching Huang5b374792014-08-19 15:25:22 +08004252 writel(0x20, pmuD->reset_request);
Nick Chengae52e7f2010-06-18 15:39:12 +08004253 } else {
Nick Chengcdd3cb12010-07-13 20:03:04 +08004254 pci_write_config_byte(acb->pdev, 0x84, 0x20);
Nick Chengae52e7f2010-06-18 15:39:12 +08004255 }
Nick Chengcdd3cb12010-07-13 20:03:04 +08004256 msleep(2000);
Nick Cheng36b83de2010-05-17 11:22:42 +08004257 /* write back pci config data */
4258 for (i = 0; i < 64; i++) {
4259 pci_write_config_byte(acb->pdev, i, value[i]);
4260 }
4261 msleep(1000);
4262 return;
4263}
Ching Huang72a7f312017-12-05 09:31:59 +08004264
4265static bool arcmsr_reset_in_progress(struct AdapterControlBlock *acb)
4266{
4267 bool rtn = true;
4268
4269 switch(acb->adapter_type) {
4270 case ACB_ADAPTER_TYPE_A:{
4271 struct MessageUnit_A __iomem *reg = acb->pmuA;
4272 rtn = ((readl(&reg->outbound_msgaddr1) &
4273 ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) ? true : false;
4274 }
4275 break;
4276 case ACB_ADAPTER_TYPE_B:{
4277 struct MessageUnit_B *reg = acb->pmuB;
4278 rtn = ((readl(reg->iop2drv_doorbell) &
4279 ARCMSR_MESSAGE_FIRMWARE_OK) == 0) ? true : false;
4280 }
4281 break;
4282 case ACB_ADAPTER_TYPE_C:{
4283 struct MessageUnit_C __iomem *reg = acb->pmuC;
4284 rtn = (readl(&reg->host_diagnostic) & 0x04) ? true : false;
4285 }
4286 break;
4287 case ACB_ADAPTER_TYPE_D:{
4288 struct MessageUnit_D *reg = acb->pmuD;
4289 rtn = ((readl(reg->sample_at_reset) & 0x80) == 0) ?
4290 true : false;
4291 }
4292 break;
Ching Huang23509022017-12-05 09:35:34 +08004293 case ACB_ADAPTER_TYPE_E:{
4294 struct MessageUnit_E __iomem *reg = acb->pmuE;
4295 rtn = (readl(&reg->host_diagnostic_3xxx) &
4296 ARCMSR_ARC188X_RESET_ADAPTER) ? true : false;
4297 }
4298 break;
Ching Huang72a7f312017-12-05 09:31:59 +08004299 }
4300 return rtn;
4301}
4302
Erich Chen1c57e862006-07-12 08:59:32 -07004303static void arcmsr_iop_init(struct AdapterControlBlock *acb)
4304{
Nick Cheng1a4f5502007-09-13 17:26:40 +08004305 uint32_t intmask_org;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004306 /* disable all outbound interrupt */
4307 intmask_org = arcmsr_disable_outbound_ints(acb);
Nick Cheng76d78302008-02-04 23:53:24 -08004308 arcmsr_wait_firmware_ready(acb);
4309 arcmsr_iop_confirm(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004310 /*start background rebuild*/
4311 arcmsr_start_adapter_bgrb(acb);
4312 /* empty doorbell Qbuffer if door bell ringed */
4313 arcmsr_clear_doorbell_queue_buffer(acb);
Nick Cheng76d78302008-02-04 23:53:24 -08004314 arcmsr_enable_eoi_mode(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08004315 /* enable outbound Post Queue,outbound doorbell Interrupt */
4316 arcmsr_enable_outbound_ints(acb, intmask_org);
Erich Chen1c57e862006-07-12 08:59:32 -07004317 acb->acb_flags |= ACB_F_IOP_INITED;
4318}
4319
Nick Cheng36b83de2010-05-17 11:22:42 +08004320static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07004321{
Erich Chen1c57e862006-07-12 08:59:32 -07004322 struct CommandControlBlock *ccb;
4323 uint32_t intmask_org;
Nick Cheng36b83de2010-05-17 11:22:42 +08004324 uint8_t rtnval = 0x00;
Erich Chen1c57e862006-07-12 08:59:32 -07004325 int i = 0;
NickCheng97b99122011-01-06 17:32:41 +08004326 unsigned long flags;
4327
Erich Chen1c57e862006-07-12 08:59:32 -07004328 if (atomic_read(&acb->ccboutstandingcount) != 0) {
Erich Chen1c57e862006-07-12 08:59:32 -07004329 /* disable all outbound interrupt */
4330 intmask_org = arcmsr_disable_outbound_ints(acb);
Nick Cheng36b83de2010-05-17 11:22:42 +08004331 /* talk to iop 331 outstanding command aborted */
4332 rtnval = arcmsr_abort_allcmd(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07004333 /* clear all outbound posted Q */
Nick Cheng1a4f5502007-09-13 17:26:40 +08004334 arcmsr_done4abort_postqueue(acb);
Ching Huangd076e4a2017-12-05 09:44:23 +08004335 for (i = 0; i < acb->maxFreeCCB; i++) {
Erich Chen1c57e862006-07-12 08:59:32 -07004336 ccb = acb->pccb_pool[i];
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08004337 if (ccb->startdone == ARCMSR_CCB_START) {
NickCheng97b99122011-01-06 17:32:41 +08004338 scsi_dma_unmap(ccb->pcmd);
4339 ccb->startdone = ARCMSR_CCB_DONE;
4340 ccb->ccb_flags = 0;
4341 spin_lock_irqsave(&acb->ccblist_lock, flags);
4342 list_add_tail(&ccb->list, &acb->ccb_free_list);
4343 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07004344 }
4345 }
Nick Cheng36b83de2010-05-17 11:22:42 +08004346 atomic_set(&acb->ccboutstandingcount, 0);
Erich Chen1c57e862006-07-12 08:59:32 -07004347 /* enable all outbound interrupt */
4348 arcmsr_enable_outbound_ints(acb, intmask_org);
Nick Cheng36b83de2010-05-17 11:22:42 +08004349 return rtnval;
Erich Chen1c57e862006-07-12 08:59:32 -07004350 }
Nick Cheng36b83de2010-05-17 11:22:42 +08004351 return rtnval;
Erich Chen1c57e862006-07-12 08:59:32 -07004352}
4353
4354static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
4355{
NickCheng97b99122011-01-06 17:32:41 +08004356 struct AdapterControlBlock *acb;
Nick Chengae52e7f2010-06-18 15:39:12 +08004357 int retry_count = 0;
4358 int rtn = FAILED;
Nick Chengae52e7f2010-06-18 15:39:12 +08004359 acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
Ching Huangc4c1adb2018-03-15 14:33:36 +08004360 if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
4361 return SUCCESS;
Ching Huang72a7f312017-12-05 09:31:59 +08004362 pr_notice("arcmsr: executing bus reset eh.....num_resets = %d,"
4363 " num_aborts = %d \n", acb->num_resets, acb->num_aborts);
Nick Cheng36b83de2010-05-17 11:22:42 +08004364 acb->num_resets++;
Nick Cheng36b83de2010-05-17 11:22:42 +08004365
Ching Huang72a7f312017-12-05 09:31:59 +08004366 if (acb->acb_flags & ACB_F_BUS_RESET) {
4367 long timeout;
Ching Huang852c3f32017-12-05 10:18:47 +08004368 pr_notice("arcmsr: there is a bus reset eh proceeding...\n");
Ching Huang72a7f312017-12-05 09:31:59 +08004369 timeout = wait_event_timeout(wait_q, (acb->acb_flags
4370 & ACB_F_BUS_RESET) == 0, 220 * HZ);
4371 if (timeout)
4372 return SUCCESS;
4373 }
4374 acb->acb_flags |= ACB_F_BUS_RESET;
4375 if (!arcmsr_iop_reset(acb)) {
4376 arcmsr_hardware_reset(acb);
4377 acb->acb_flags &= ~ACB_F_IOP_INITED;
4378wait_reset_done:
4379 ssleep(ARCMSR_SLEEPTIME);
4380 if (arcmsr_reset_in_progress(acb)) {
4381 if (retry_count > ARCMSR_RETRYCOUNT) {
4382 acb->fw_flag = FW_DEADLOCK;
4383 pr_notice("arcmsr%d: waiting for hw bus reset"
4384 " return, RETRY TERMINATED!!\n",
4385 acb->host->host_no);
4386 return FAILED;
Nick Chengae52e7f2010-06-18 15:39:12 +08004387 }
Ching Huang72a7f312017-12-05 09:31:59 +08004388 retry_count++;
4389 goto wait_reset_done;
Nick Chengcdd3cb12010-07-13 20:03:04 +08004390 }
Ching Huang72a7f312017-12-05 09:31:59 +08004391 arcmsr_iop_init(acb);
4392 atomic_set(&acb->rq_map_token, 16);
4393 atomic_set(&acb->ante_token_value, 16);
4394 acb->fw_flag = FW_NORMAL;
4395 mod_timer(&acb->eternal_timer, jiffies +
4396 msecs_to_jiffies(6 * HZ));
4397 acb->acb_flags &= ~ACB_F_BUS_RESET;
4398 rtn = SUCCESS;
4399 pr_notice("arcmsr: scsi bus reset eh returns with success\n");
4400 } else {
4401 acb->acb_flags &= ~ACB_F_BUS_RESET;
4402 atomic_set(&acb->rq_map_token, 16);
4403 atomic_set(&acb->ante_token_value, 16);
4404 acb->fw_flag = FW_NORMAL;
4405 mod_timer(&acb->eternal_timer, jiffies +
4406 msecs_to_jiffies(6 * HZ));
4407 rtn = SUCCESS;
Nick Chengae52e7f2010-06-18 15:39:12 +08004408 }
4409 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07004410}
4411
Nick Chengae52e7f2010-06-18 15:39:12 +08004412static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07004413 struct CommandControlBlock *ccb)
4414{
Nick Chengae52e7f2010-06-18 15:39:12 +08004415 int rtn;
Nick Chengae52e7f2010-06-18 15:39:12 +08004416 rtn = arcmsr_polling_ccbdone(acb, ccb);
Nick Chengae52e7f2010-06-18 15:39:12 +08004417 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07004418}
4419
4420static int arcmsr_abort(struct scsi_cmnd *cmd)
4421{
4422 struct AdapterControlBlock *acb =
4423 (struct AdapterControlBlock *)cmd->device->host->hostdata;
4424 int i = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08004425 int rtn = FAILED;
Ching Huangcab5aec2014-08-19 14:47:16 +08004426 uint32_t intmask_org;
4427
Ching Huangc4c1adb2018-03-15 14:33:36 +08004428 if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
4429 return SUCCESS;
Erich Chen1c57e862006-07-12 08:59:32 -07004430 printk(KERN_NOTICE
Ching Huangcab5aec2014-08-19 14:47:16 +08004431 "arcmsr%d: abort device command of scsi id = %d lun = %d\n",
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02004432 acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);
Nick Chengae52e7f2010-06-18 15:39:12 +08004433 acb->acb_flags |= ACB_F_ABORT;
Erich Chen1c57e862006-07-12 08:59:32 -07004434 acb->num_aborts++;
Erich Chen1c57e862006-07-12 08:59:32 -07004435 /*
4436 ************************************************
4437 ** the all interrupt service routine is locked
4438 ** we need to handle it as soon as possible and exit
4439 ************************************************
4440 */
Ching Huangcab5aec2014-08-19 14:47:16 +08004441 if (!atomic_read(&acb->ccboutstandingcount)) {
4442 acb->acb_flags &= ~ACB_F_ABORT;
Nick Chengae52e7f2010-06-18 15:39:12 +08004443 return rtn;
Ching Huangcab5aec2014-08-19 14:47:16 +08004444 }
Erich Chen1c57e862006-07-12 08:59:32 -07004445
Ching Huangcab5aec2014-08-19 14:47:16 +08004446 intmask_org = arcmsr_disable_outbound_ints(acb);
Ching Huangd076e4a2017-12-05 09:44:23 +08004447 for (i = 0; i < acb->maxFreeCCB; i++) {
Erich Chen1c57e862006-07-12 08:59:32 -07004448 struct CommandControlBlock *ccb = acb->pccb_pool[i];
4449 if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
Nick Chengae52e7f2010-06-18 15:39:12 +08004450 ccb->startdone = ARCMSR_CCB_ABORTED;
4451 rtn = arcmsr_abort_one_cmd(acb, ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07004452 break;
4453 }
4454 }
Nick Chengae52e7f2010-06-18 15:39:12 +08004455 acb->acb_flags &= ~ACB_F_ABORT;
Ching Huangcab5aec2014-08-19 14:47:16 +08004456 arcmsr_enable_outbound_ints(acb, intmask_org);
Nick Chengae52e7f2010-06-18 15:39:12 +08004457 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07004458}
4459
4460static const char *arcmsr_info(struct Scsi_Host *host)
4461{
4462 struct AdapterControlBlock *acb =
4463 (struct AdapterControlBlock *) host->hostdata;
4464 static char buf[256];
4465 char *type;
4466 int raid6 = 1;
Erich Chen1c57e862006-07-12 08:59:32 -07004467 switch (acb->pdev->device) {
4468 case PCI_DEVICE_ID_ARECA_1110:
Nick Cheng1a4f5502007-09-13 17:26:40 +08004469 case PCI_DEVICE_ID_ARECA_1200:
4470 case PCI_DEVICE_ID_ARECA_1202:
Erich Chen1c57e862006-07-12 08:59:32 -07004471 case PCI_DEVICE_ID_ARECA_1210:
4472 raid6 = 0;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05004473 fallthrough;
Erich Chen1c57e862006-07-12 08:59:32 -07004474 case PCI_DEVICE_ID_ARECA_1120:
4475 case PCI_DEVICE_ID_ARECA_1130:
4476 case PCI_DEVICE_ID_ARECA_1160:
4477 case PCI_DEVICE_ID_ARECA_1170:
Nick Cheng1a4f5502007-09-13 17:26:40 +08004478 case PCI_DEVICE_ID_ARECA_1201:
Ching Huang7e315ff2015-11-25 19:49:33 +08004479 case PCI_DEVICE_ID_ARECA_1203:
Erich Chen1c57e862006-07-12 08:59:32 -07004480 case PCI_DEVICE_ID_ARECA_1220:
4481 case PCI_DEVICE_ID_ARECA_1230:
4482 case PCI_DEVICE_ID_ARECA_1260:
4483 case PCI_DEVICE_ID_ARECA_1270:
4484 case PCI_DEVICE_ID_ARECA_1280:
4485 type = "SATA";
4486 break;
Ching Huang5b374792014-08-19 15:25:22 +08004487 case PCI_DEVICE_ID_ARECA_1214:
Erich Chen1c57e862006-07-12 08:59:32 -07004488 case PCI_DEVICE_ID_ARECA_1380:
4489 case PCI_DEVICE_ID_ARECA_1381:
4490 case PCI_DEVICE_ID_ARECA_1680:
4491 case PCI_DEVICE_ID_ARECA_1681:
Nick Chengcdd3cb12010-07-13 20:03:04 +08004492 case PCI_DEVICE_ID_ARECA_1880:
Ching Huang23509022017-12-05 09:35:34 +08004493 case PCI_DEVICE_ID_ARECA_1884:
Ching Huangaaa64f62014-08-19 15:22:45 +08004494 type = "SAS/SATA";
Erich Chen1c57e862006-07-12 08:59:32 -07004495 break;
4496 default:
Ching Huangaaa64f62014-08-19 15:22:45 +08004497 type = "unknown";
4498 raid6 = 0;
Erich Chen1c57e862006-07-12 08:59:32 -07004499 break;
4500 }
Ching Huangaaa64f62014-08-19 15:22:45 +08004501 sprintf(buf, "Areca %s RAID Controller %s\narcmsr version %s\n",
4502 type, raid6 ? "(RAID6 capable)" : "", ARCMSR_DRIVER_VERSION);
Erich Chen1c57e862006-07-12 08:59:32 -07004503 return buf;
4504}