Commit | Line | Data |
---|---|---|
1c57e86d EC |
1 | /* |
2 | ******************************************************************************* | |
3 | ** O.S : Linux | |
4 | ** FILE NAME : arcmsr_hba.c | |
aaa64f69 CH |
5 | ** BY : Nick Cheng, C.L. Huang |
6 | ** Description: SCSI RAID Device Driver for Areca RAID Controller | |
1c57e86d | 7 | ******************************************************************************* |
aaa64f69 | 8 | ** Copyright (C) 2002 - 2014, Areca Technology Corporation All rights reserved |
1c57e86d EC |
9 | ** |
10 | ** Web site: www.areca.com.tw | |
1a4f550a | 11 | ** E-mail: support@areca.com.tw |
1c57e86d EC |
12 | ** |
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 | |
44 | ** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt | |
45 | ******************************************************************************* | |
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> | |
a7c8962b | 58 | #include <linux/slab.h> |
1c57e86d | 59 | #include <linux/pci.h> |
a1f6e021 | 60 | #include <linux/aer.h> |
2e9feb43 | 61 | #include <linux/circ_buf.h> |
1c57e86d EC |
62 | #include <asm/dma.h> |
63 | #include <asm/io.h> | |
1c57e86d EC |
64 | #include <asm/uaccess.h> |
65 | #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" | |
aaa64f69 CH |
73 | MODULE_AUTHOR("Nick Cheng, C.L. Huang <support@areca.com.tw>"); |
74 | MODULE_DESCRIPTION("Areca ARC11xx/12xx/16xx/188x SAS/SATA RAID Controller Driver"); | |
1c57e86d EC |
75 | MODULE_LICENSE("Dual BSD/GPL"); |
76 | MODULE_VERSION(ARCMSR_DRIVER_VERSION); | |
8b7eb86f TH |
77 | |
78 | #define ARCMSR_SLEEPTIME 10 | |
79 | #define ARCMSR_RETRYCOUNT 12 | |
80 | ||
c10b1d54 | 81 | static wait_queue_head_t wait_q; |
1a4f550a NC |
82 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, |
83 | struct scsi_cmnd *cmd); | |
84 | static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); | |
1c57e86d EC |
85 | static int arcmsr_abort(struct scsi_cmnd *); |
86 | static int arcmsr_bus_reset(struct scsi_cmnd *); | |
87 | static int arcmsr_bios_param(struct scsi_device *sdev, | |
1a4f550a | 88 | struct block_device *bdev, sector_t capacity, int *info); |
f281233d | 89 | static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); |
1c57e86d EC |
90 | static int arcmsr_probe(struct pci_dev *pdev, |
91 | const struct pci_device_id *id); | |
61cda87f CH |
92 | static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state); |
93 | static int arcmsr_resume(struct pci_dev *pdev); | |
1c57e86d EC |
94 | static void arcmsr_remove(struct pci_dev *pdev); |
95 | static void arcmsr_shutdown(struct pci_dev *pdev); | |
96 | static void arcmsr_iop_init(struct AdapterControlBlock *acb); | |
97 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); | |
1a4f550a | 98 | static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); |
61cda87f CH |
99 | static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, |
100 | u32 intmask_org); | |
1c57e86d | 101 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); |
626fa32c CH |
102 | static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb); |
103 | static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb); | |
36b83ded | 104 | static void arcmsr_request_device_map(unsigned long pacb); |
626fa32c CH |
105 | static void arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb); |
106 | static void arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb); | |
107 | static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb); | |
36b83ded | 108 | static void arcmsr_message_isr_bh_fn(struct work_struct *work); |
ae52e7f0 | 109 | static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); |
36b83ded | 110 | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); |
626fa32c | 111 | static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *pACB); |
5b37479a | 112 | static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb); |
cdd3cb15 | 113 | static void arcmsr_hardware_reset(struct AdapterControlBlock *acb); |
1c57e86d EC |
114 | static const char *arcmsr_info(struct Scsi_Host *); |
115 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); | |
b4eb6ae9 | 116 | static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *); |
7e315ffd | 117 | static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb); |
db5ed4df | 118 | static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) |
1c57e86d EC |
119 | { |
120 | if (queue_depth > ARCMSR_MAX_CMD_PERLUN) | |
121 | queue_depth = ARCMSR_MAX_CMD_PERLUN; | |
db5ed4df | 122 | return scsi_change_queue_depth(sdev, queue_depth); |
1c57e86d EC |
123 | } |
124 | ||
125 | static struct scsi_host_template arcmsr_scsi_host_template = { | |
126 | .module = THIS_MODULE, | |
aaa64f69 | 127 | .name = "Areca SAS/SATA RAID driver", |
1c57e86d EC |
128 | .info = arcmsr_info, |
129 | .queuecommand = arcmsr_queue_command, | |
cdd3cb15 | 130 | .eh_abort_handler = arcmsr_abort, |
1c57e86d EC |
131 | .eh_bus_reset_handler = arcmsr_bus_reset, |
132 | .bios_param = arcmsr_bios_param, | |
133 | .change_queue_depth = arcmsr_adjust_disk_queue_depth, | |
3df824af | 134 | .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, |
cdd3cb15 NC |
135 | .this_id = ARCMSR_SCSI_INITIATOR_ID, |
136 | .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, | |
137 | .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, | |
1c57e86d EC |
138 | .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, |
139 | .use_clustering = ENABLE_CLUSTERING, | |
140 | .shost_attrs = arcmsr_host_attrs, | |
54b2b50c | 141 | .no_write_same = 1, |
1c57e86d | 142 | }; |
8b7c9942 | 143 | |
1c57e86d | 144 | static struct pci_device_id arcmsr_device_id_table[] = { |
8b7c9942 CH |
145 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110), |
146 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
147 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120), | |
148 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
149 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130), | |
150 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
151 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160), | |
152 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
153 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170), | |
154 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
155 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200), | |
156 | .driver_data = ACB_ADAPTER_TYPE_B}, | |
157 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201), | |
158 | .driver_data = ACB_ADAPTER_TYPE_B}, | |
159 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202), | |
160 | .driver_data = ACB_ADAPTER_TYPE_B}, | |
7e315ffd CH |
161 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203), |
162 | .driver_data = ACB_ADAPTER_TYPE_B}, | |
8b7c9942 CH |
163 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210), |
164 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
5b37479a CH |
165 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214), |
166 | .driver_data = ACB_ADAPTER_TYPE_D}, | |
8b7c9942 CH |
167 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220), |
168 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
169 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230), | |
170 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
171 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260), | |
172 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
173 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270), | |
174 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
175 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280), | |
176 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
177 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380), | |
178 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
179 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381), | |
180 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
181 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680), | |
182 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
183 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681), | |
184 | .driver_data = ACB_ADAPTER_TYPE_A}, | |
185 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880), | |
186 | .driver_data = ACB_ADAPTER_TYPE_C}, | |
1c57e86d EC |
187 | {0, 0}, /* Terminating entry */ |
188 | }; | |
189 | MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); | |
8b7c9942 | 190 | |
1c57e86d EC |
191 | static struct pci_driver arcmsr_pci_driver = { |
192 | .name = "arcmsr", | |
cdd3cb15 | 193 | .id_table = arcmsr_device_id_table, |
1c57e86d EC |
194 | .probe = arcmsr_probe, |
195 | .remove = arcmsr_remove, | |
61cda87f CH |
196 | .suspend = arcmsr_suspend, |
197 | .resume = arcmsr_resume, | |
a1f6e021 | 198 | .shutdown = arcmsr_shutdown, |
1c57e86d | 199 | }; |
cdd3cb15 NC |
200 | /* |
201 | **************************************************************************** | |
202 | **************************************************************************** | |
203 | */ | |
1c57e86d | 204 | |
626fa32c | 205 | static void arcmsr_free_mu(struct AdapterControlBlock *acb) |
ae52e7f0 NC |
206 | { |
207 | switch (acb->adapter_type) { | |
5b37479a CH |
208 | case ACB_ADAPTER_TYPE_B: |
209 | case ACB_ADAPTER_TYPE_D: { | |
6e38adfc CH |
210 | dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize, |
211 | acb->dma_coherent2, acb->dma_coherent_handle2); | |
212 | break; | |
ae52e7f0 NC |
213 | } |
214 | } | |
215 | } | |
216 | ||
217 | static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) | |
218 | { | |
219 | struct pci_dev *pdev = acb->pdev; | |
cdd3cb15 | 220 | switch (acb->adapter_type){ |
ae52e7f0 | 221 | case ACB_ADAPTER_TYPE_A:{ |
cdd3cb15 | 222 | acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0)); |
ae52e7f0 NC |
223 | if (!acb->pmuA) { |
224 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | |
225 | return false; | |
226 | } | |
227 | break; | |
228 | } | |
229 | case ACB_ADAPTER_TYPE_B:{ | |
230 | void __iomem *mem_base0, *mem_base1; | |
231 | mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); | |
232 | if (!mem_base0) { | |
233 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | |
234 | return false; | |
235 | } | |
236 | mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); | |
237 | if (!mem_base1) { | |
238 | iounmap(mem_base0); | |
239 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | |
240 | return false; | |
241 | } | |
242 | acb->mem_base0 = mem_base0; | |
243 | acb->mem_base1 = mem_base1; | |
cdd3cb15 NC |
244 | break; |
245 | } | |
246 | case ACB_ADAPTER_TYPE_C:{ | |
247 | acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); | |
248 | if (!acb->pmuC) { | |
249 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | |
250 | return false; | |
251 | } | |
252 | if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | |
253 | writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/ | |
254 | return true; | |
255 | } | |
256 | break; | |
ae52e7f0 | 257 | } |
5b37479a CH |
258 | case ACB_ADAPTER_TYPE_D: { |
259 | void __iomem *mem_base0; | |
260 | unsigned long addr, range, flags; | |
261 | ||
262 | addr = (unsigned long)pci_resource_start(pdev, 0); | |
263 | range = pci_resource_len(pdev, 0); | |
264 | flags = pci_resource_flags(pdev, 0); | |
92b19ff5 | 265 | mem_base0 = ioremap(addr, range); |
5b37479a CH |
266 | if (!mem_base0) { |
267 | pr_notice("arcmsr%d: memory mapping region fail\n", | |
268 | acb->host->host_no); | |
269 | return false; | |
270 | } | |
271 | acb->mem_base0 = mem_base0; | |
272 | break; | |
273 | } | |
ae52e7f0 NC |
274 | } |
275 | return true; | |
276 | } | |
277 | ||
278 | static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) | |
279 | { | |
280 | switch (acb->adapter_type) { | |
cdd3cb15 NC |
281 | case ACB_ADAPTER_TYPE_A:{ |
282 | iounmap(acb->pmuA); | |
283 | } | |
284 | break; | |
285 | case ACB_ADAPTER_TYPE_B:{ | |
286 | iounmap(acb->mem_base0); | |
287 | iounmap(acb->mem_base1); | |
288 | } | |
289 | ||
290 | break; | |
291 | case ACB_ADAPTER_TYPE_C:{ | |
292 | iounmap(acb->pmuC); | |
293 | } | |
5b37479a CH |
294 | break; |
295 | case ACB_ADAPTER_TYPE_D: | |
296 | iounmap(acb->mem_base0); | |
297 | break; | |
ae52e7f0 NC |
298 | } |
299 | } | |
300 | ||
7d12e780 | 301 | static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) |
1c57e86d EC |
302 | { |
303 | irqreturn_t handle_state; | |
1a4f550a | 304 | struct AdapterControlBlock *acb = dev_id; |
1c57e86d | 305 | |
1c57e86d | 306 | handle_state = arcmsr_interrupt(acb); |
1c57e86d EC |
307 | return handle_state; |
308 | } | |
309 | ||
310 | static int arcmsr_bios_param(struct scsi_device *sdev, | |
311 | struct block_device *bdev, sector_t capacity, int *geom) | |
312 | { | |
313 | int ret, heads, sectors, cylinders, total_capacity; | |
314 | unsigned char *buffer;/* return copy of block device's partition table */ | |
315 | ||
316 | buffer = scsi_bios_ptable(bdev); | |
317 | if (buffer) { | |
318 | ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]); | |
319 | kfree(buffer); | |
320 | if (ret != -1) | |
321 | return ret; | |
322 | } | |
323 | total_capacity = capacity; | |
324 | heads = 64; | |
325 | sectors = 32; | |
326 | cylinders = total_capacity / (heads * sectors); | |
327 | if (cylinders > 1024) { | |
328 | heads = 255; | |
329 | sectors = 63; | |
330 | cylinders = total_capacity / (heads * sectors); | |
331 | } | |
332 | geom[0] = heads; | |
333 | geom[1] = sectors; | |
334 | geom[2] = cylinders; | |
335 | return 0; | |
336 | } | |
337 | ||
626fa32c | 338 | static uint8_t arcmsr_hbaA_wait_msgint_ready(struct AdapterControlBlock *acb) |
ae52e7f0 NC |
339 | { |
340 | struct MessageUnit_A __iomem *reg = acb->pmuA; | |
8b7eb86f TH |
341 | int i; |
342 | ||
343 | for (i = 0; i < 2000; i++) { | |
344 | if (readl(®->outbound_intstatus) & | |
345 | ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { | |
346 | writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, | |
347 | ®->outbound_intstatus); | |
348 | return true; | |
349 | } | |
350 | msleep(10); | |
351 | } /* max 20 seconds */ | |
ae52e7f0 | 352 | |
cdd3cb15 | 353 | return false; |
ae52e7f0 NC |
354 | } |
355 | ||
626fa32c | 356 | static uint8_t arcmsr_hbaB_wait_msgint_ready(struct AdapterControlBlock *acb) |
1a4f550a | 357 | { |
ae52e7f0 | 358 | struct MessageUnit_B *reg = acb->pmuB; |
8b7eb86f TH |
359 | int i; |
360 | ||
361 | for (i = 0; i < 2000; i++) { | |
362 | if (readl(reg->iop2drv_doorbell) | |
363 | & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { | |
364 | writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, | |
365 | reg->iop2drv_doorbell); | |
366 | writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, | |
367 | reg->drv2iop_doorbell); | |
368 | return true; | |
369 | } | |
370 | msleep(10); | |
371 | } /* max 20 seconds */ | |
ae52e7f0 | 372 | |
cdd3cb15 | 373 | return false; |
ae52e7f0 NC |
374 | } |
375 | ||
626fa32c | 376 | static uint8_t arcmsr_hbaC_wait_msgint_ready(struct AdapterControlBlock *pACB) |
cdd3cb15 | 377 | { |
c10b1d54 | 378 | struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; |
8b7eb86f TH |
379 | int i; |
380 | ||
381 | for (i = 0; i < 2000; i++) { | |
382 | if (readl(&phbcmu->outbound_doorbell) | |
383 | & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | |
384 | writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, | |
385 | &phbcmu->outbound_doorbell_clear); /*clear interrupt*/ | |
386 | return true; | |
387 | } | |
388 | msleep(10); | |
389 | } /* max 20 seconds */ | |
390 | ||
cdd3cb15 NC |
391 | return false; |
392 | } | |
8b7eb86f | 393 | |
5b37479a CH |
394 | static bool arcmsr_hbaD_wait_msgint_ready(struct AdapterControlBlock *pACB) |
395 | { | |
396 | struct MessageUnit_D *reg = pACB->pmuD; | |
397 | int i; | |
398 | ||
399 | for (i = 0; i < 2000; i++) { | |
400 | if (readl(reg->outbound_doorbell) | |
401 | & ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) { | |
402 | writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE, | |
403 | reg->outbound_doorbell); | |
404 | return true; | |
405 | } | |
406 | msleep(10); | |
407 | } /* max 20 seconds */ | |
408 | return false; | |
409 | } | |
410 | ||
626fa32c | 411 | static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb) |
ae52e7f0 NC |
412 | { |
413 | struct MessageUnit_A __iomem *reg = acb->pmuA; | |
414 | int retry_count = 30; | |
ae52e7f0 NC |
415 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); |
416 | do { | |
626fa32c | 417 | if (arcmsr_hbaA_wait_msgint_ready(acb)) |
ae52e7f0 NC |
418 | break; |
419 | else { | |
420 | retry_count--; | |
421 | printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ | |
422 | timeout, retry count down = %d \n", acb->host->host_no, retry_count); | |
423 | } | |
424 | } while (retry_count != 0); | |
425 | } | |
426 | ||
626fa32c | 427 | static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb) |
ae52e7f0 NC |
428 | { |
429 | struct MessageUnit_B *reg = acb->pmuB; | |
430 | int retry_count = 30; | |
ae52e7f0 NC |
431 | writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); |
432 | do { | |
626fa32c | 433 | if (arcmsr_hbaB_wait_msgint_ready(acb)) |
ae52e7f0 NC |
434 | break; |
435 | else { | |
436 | retry_count--; | |
437 | printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ | |
438 | timeout,retry count down = %d \n", acb->host->host_no, retry_count); | |
439 | } | |
440 | } while (retry_count != 0); | |
441 | } | |
442 | ||
626fa32c | 443 | static void arcmsr_hbaC_flush_cache(struct AdapterControlBlock *pACB) |
cdd3cb15 | 444 | { |
c10b1d54 | 445 | struct MessageUnit_C __iomem *reg = pACB->pmuC; |
cdd3cb15 NC |
446 | int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */ |
447 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); | |
448 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
449 | do { | |
626fa32c | 450 | if (arcmsr_hbaC_wait_msgint_ready(pACB)) { |
cdd3cb15 NC |
451 | break; |
452 | } else { | |
453 | retry_count--; | |
454 | printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ | |
455 | timeout,retry count down = %d \n", pACB->host->host_no, retry_count); | |
456 | } | |
457 | } while (retry_count != 0); | |
458 | return; | |
459 | } | |
5b37479a CH |
460 | |
461 | static void arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB) | |
462 | { | |
463 | int retry_count = 15; | |
464 | struct MessageUnit_D *reg = pACB->pmuD; | |
465 | ||
466 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, reg->inbound_msgaddr0); | |
467 | do { | |
468 | if (arcmsr_hbaD_wait_msgint_ready(pACB)) | |
469 | break; | |
470 | ||
471 | retry_count--; | |
472 | pr_notice("arcmsr%d: wait 'flush adapter " | |
473 | "cache' timeout, retry count down = %d\n", | |
474 | pACB->host->host_no, retry_count); | |
475 | } while (retry_count != 0); | |
476 | } | |
477 | ||
ae52e7f0 NC |
478 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) |
479 | { | |
1a4f550a | 480 | switch (acb->adapter_type) { |
1c57e86d | 481 | |
1a4f550a | 482 | case ACB_ADAPTER_TYPE_A: { |
626fa32c | 483 | arcmsr_hbaA_flush_cache(acb); |
ae52e7f0 NC |
484 | } |
485 | break; | |
1a4f550a | 486 | |
ae52e7f0 | 487 | case ACB_ADAPTER_TYPE_B: { |
626fa32c | 488 | arcmsr_hbaB_flush_cache(acb); |
1a4f550a | 489 | } |
cdd3cb15 NC |
490 | break; |
491 | case ACB_ADAPTER_TYPE_C: { | |
626fa32c | 492 | arcmsr_hbaC_flush_cache(acb); |
cdd3cb15 | 493 | } |
5b37479a CH |
494 | break; |
495 | case ACB_ADAPTER_TYPE_D: | |
496 | arcmsr_hbaD_flush_cache(acb); | |
497 | break; | |
ae52e7f0 NC |
498 | } |
499 | } | |
1a4f550a | 500 | |
02040670 CH |
501 | static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) |
502 | { | |
503 | bool rtn = true; | |
504 | void *dma_coherent; | |
505 | dma_addr_t dma_coherent_handle; | |
506 | struct pci_dev *pdev = acb->pdev; | |
507 | ||
508 | switch (acb->adapter_type) { | |
509 | case ACB_ADAPTER_TYPE_B: { | |
510 | struct MessageUnit_B *reg; | |
511 | acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32); | |
512 | dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, | |
513 | &dma_coherent_handle, GFP_KERNEL); | |
514 | if (!dma_coherent) { | |
515 | pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); | |
516 | return false; | |
517 | } | |
518 | acb->dma_coherent_handle2 = dma_coherent_handle; | |
519 | acb->dma_coherent2 = dma_coherent; | |
520 | reg = (struct MessageUnit_B *)dma_coherent; | |
521 | acb->pmuB = reg; | |
522 | if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) { | |
523 | reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203); | |
524 | reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203); | |
525 | reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203); | |
526 | reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203); | |
527 | } else { | |
528 | reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL); | |
529 | reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK); | |
530 | reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL); | |
531 | reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK); | |
532 | } | |
533 | reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER); | |
534 | reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER); | |
535 | reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER); | |
536 | } | |
537 | break; | |
538 | case ACB_ADAPTER_TYPE_D: { | |
539 | struct MessageUnit_D *reg; | |
540 | ||
541 | acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32); | |
542 | dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, | |
543 | &dma_coherent_handle, GFP_KERNEL); | |
544 | if (!dma_coherent) { | |
545 | pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); | |
546 | return false; | |
547 | } | |
548 | acb->dma_coherent_handle2 = dma_coherent_handle; | |
549 | acb->dma_coherent2 = dma_coherent; | |
550 | reg = (struct MessageUnit_D *)dma_coherent; | |
551 | acb->pmuD = reg; | |
552 | reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID); | |
553 | reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION); | |
554 | reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK); | |
555 | reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET); | |
556 | reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST); | |
557 | reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS); | |
558 | reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE); | |
559 | reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0); | |
560 | reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1); | |
561 | reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0); | |
562 | reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1); | |
563 | reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL); | |
564 | reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL); | |
565 | reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE); | |
566 | reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW); | |
567 | reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH); | |
568 | reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER); | |
569 | reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW); | |
570 | reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH); | |
571 | reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER); | |
572 | reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER); | |
573 | reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE); | |
574 | reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE); | |
575 | reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER); | |
576 | reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER); | |
577 | reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER); | |
578 | } | |
579 | break; | |
580 | default: | |
581 | break; | |
582 | } | |
583 | return rtn; | |
584 | } | |
585 | ||
ae52e7f0 NC |
586 | static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) |
587 | { | |
cdd3cb15 NC |
588 | struct pci_dev *pdev = acb->pdev; |
589 | void *dma_coherent; | |
590 | dma_addr_t dma_coherent_handle; | |
591 | struct CommandControlBlock *ccb_tmp; | |
592 | int i = 0, j = 0; | |
593 | dma_addr_t cdb_phyaddr; | |
87f76152 | 594 | unsigned long roundup_ccbsize; |
cdd3cb15 NC |
595 | unsigned long max_xfer_len; |
596 | unsigned long max_sg_entrys; | |
597 | uint32_t firm_config_version; | |
87f76152 | 598 | |
cdd3cb15 NC |
599 | for (i = 0; i < ARCMSR_MAX_TARGETID; i++) |
600 | for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) | |
601 | acb->devstate[i][j] = ARECA_RAID_GONE; | |
602 | ||
603 | max_xfer_len = ARCMSR_MAX_XFER_LEN; | |
604 | max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; | |
605 | firm_config_version = acb->firm_cfg_version; | |
606 | if((firm_config_version & 0xFF) >= 3){ | |
607 | max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ | |
87f76152 | 608 | max_sg_entrys = (max_xfer_len/4096); |
cdd3cb15 NC |
609 | } |
610 | acb->host->max_sectors = max_xfer_len/512; | |
611 | acb->host->sg_tablesize = max_sg_entrys; | |
612 | roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); | |
87f76152 | 613 | acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; |
cdd3cb15 NC |
614 | dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); |
615 | if(!dma_coherent){ | |
87f76152 | 616 | printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no); |
cdd3cb15 NC |
617 | return -ENOMEM; |
618 | } | |
619 | acb->dma_coherent = dma_coherent; | |
620 | acb->dma_coherent_handle = dma_coherent_handle; | |
621 | memset(dma_coherent, 0, acb->uncache_size); | |
cdd3cb15 NC |
622 | ccb_tmp = dma_coherent; |
623 | acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; | |
624 | for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ | |
625 | cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); | |
5b37479a CH |
626 | switch (acb->adapter_type) { |
627 | case ACB_ADAPTER_TYPE_A: | |
628 | case ACB_ADAPTER_TYPE_B: | |
629 | ccb_tmp->cdb_phyaddr = cdb_phyaddr >> 5; | |
630 | break; | |
631 | case ACB_ADAPTER_TYPE_C: | |
632 | case ACB_ADAPTER_TYPE_D: | |
633 | ccb_tmp->cdb_phyaddr = cdb_phyaddr; | |
634 | break; | |
635 | } | |
cdd3cb15 NC |
636 | acb->pccb_pool[i] = ccb_tmp; |
637 | ccb_tmp->acb = acb; | |
638 | INIT_LIST_HEAD(&ccb_tmp->list); | |
639 | list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); | |
640 | ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); | |
641 | dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; | |
1a4f550a | 642 | } |
1c57e86d EC |
643 | return 0; |
644 | } | |
36b83ded | 645 | |
cdd3cb15 NC |
646 | static void arcmsr_message_isr_bh_fn(struct work_struct *work) |
647 | { | |
12aad947 CH |
648 | struct AdapterControlBlock *acb = container_of(work, |
649 | struct AdapterControlBlock, arcmsr_do_message_isr_bh); | |
650 | char *acb_dev_map = (char *)acb->device_map; | |
651 | uint32_t __iomem *signature = NULL; | |
652 | char __iomem *devicemap = NULL; | |
653 | int target, lun; | |
654 | struct scsi_device *psdev; | |
655 | char diff, temp; | |
656 | ||
36b83ded | 657 | switch (acb->adapter_type) { |
12aad947 CH |
658 | case ACB_ADAPTER_TYPE_A: { |
659 | struct MessageUnit_A __iomem *reg = acb->pmuA; | |
36b83ded | 660 | |
12aad947 CH |
661 | signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); |
662 | devicemap = (char __iomem *)(®->message_rwbuffer[21]); | |
cdd3cb15 | 663 | break; |
12aad947 CH |
664 | } |
665 | case ACB_ADAPTER_TYPE_B: { | |
666 | struct MessageUnit_B *reg = acb->pmuB; | |
667 | ||
668 | signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); | |
669 | devicemap = (char __iomem *)(®->message_rwbuffer[21]); | |
670 | break; | |
671 | } | |
672 | case ACB_ADAPTER_TYPE_C: { | |
673 | struct MessageUnit_C __iomem *reg = acb->pmuC; | |
674 | ||
675 | signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); | |
676 | devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); | |
677 | break; | |
678 | } | |
5b37479a CH |
679 | case ACB_ADAPTER_TYPE_D: { |
680 | struct MessageUnit_D *reg = acb->pmuD; | |
681 | ||
682 | signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); | |
683 | devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); | |
684 | break; | |
685 | } | |
12aad947 CH |
686 | } |
687 | atomic_inc(&acb->rq_map_token); | |
688 | if (readl(signature) != ARCMSR_SIGNATURE_GET_CONFIG) | |
689 | return; | |
690 | for (target = 0; target < ARCMSR_MAX_TARGETID - 1; | |
691 | target++) { | |
692 | temp = readb(devicemap); | |
693 | diff = (*acb_dev_map) ^ temp; | |
694 | if (diff != 0) { | |
695 | *acb_dev_map = temp; | |
696 | for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; | |
697 | lun++) { | |
698 | if ((diff & 0x01) == 1 && | |
699 | (temp & 0x01) == 1) { | |
700 | scsi_add_device(acb->host, | |
701 | 0, target, lun); | |
702 | } else if ((diff & 0x01) == 1 | |
703 | && (temp & 0x01) == 0) { | |
704 | psdev = scsi_device_lookup(acb->host, | |
705 | 0, target, lun); | |
706 | if (psdev != NULL) { | |
707 | scsi_remove_device(psdev); | |
708 | scsi_device_put(psdev); | |
36b83ded | 709 | } |
36b83ded | 710 | } |
12aad947 CH |
711 | temp >>= 1; |
712 | diff >>= 1; | |
36b83ded NC |
713 | } |
714 | } | |
12aad947 CH |
715 | devicemap++; |
716 | acb_dev_map++; | |
36b83ded NC |
717 | } |
718 | } | |
1c57e86d | 719 | |
1d1166ea CH |
720 | static int |
721 | arcmsr_request_irq(struct pci_dev *pdev, struct AdapterControlBlock *acb) | |
722 | { | |
723 | int i, j, r; | |
724 | struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS]; | |
725 | ||
726 | for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++) | |
727 | entries[i].entry = i; | |
728 | r = pci_enable_msix_range(pdev, entries, 1, ARCMST_NUM_MSIX_VECTORS); | |
729 | if (r < 0) | |
730 | goto msi_int; | |
731 | acb->msix_vector_count = r; | |
732 | for (i = 0; i < r; i++) { | |
733 | if (request_irq(entries[i].vector, | |
734 | arcmsr_do_interrupt, 0, "arcmsr", acb)) { | |
735 | pr_warn("arcmsr%d: request_irq =%d failed!\n", | |
736 | acb->host->host_no, entries[i].vector); | |
737 | for (j = 0 ; j < i ; j++) | |
738 | free_irq(entries[j].vector, acb); | |
739 | pci_disable_msix(pdev); | |
740 | goto msi_int; | |
741 | } | |
742 | acb->entries[i] = entries[i]; | |
743 | } | |
744 | acb->acb_flags |= ACB_F_MSIX_ENABLED; | |
745 | pr_info("arcmsr%d: msi-x enabled\n", acb->host->host_no); | |
746 | return SUCCESS; | |
747 | msi_int: | |
748 | if (pci_enable_msi_exact(pdev, 1) < 0) | |
749 | goto legacy_int; | |
750 | if (request_irq(pdev->irq, arcmsr_do_interrupt, | |
751 | IRQF_SHARED, "arcmsr", acb)) { | |
752 | pr_warn("arcmsr%d: request_irq =%d failed!\n", | |
753 | acb->host->host_no, pdev->irq); | |
754 | pci_disable_msi(pdev); | |
755 | goto legacy_int; | |
756 | } | |
757 | acb->acb_flags |= ACB_F_MSI_ENABLED; | |
758 | pr_info("arcmsr%d: msi enabled\n", acb->host->host_no); | |
759 | return SUCCESS; | |
760 | legacy_int: | |
761 | if (request_irq(pdev->irq, arcmsr_do_interrupt, | |
762 | IRQF_SHARED, "arcmsr", acb)) { | |
763 | pr_warn("arcmsr%d: request_irq = %d failed!\n", | |
764 | acb->host->host_no, pdev->irq); | |
765 | return FAILED; | |
766 | } | |
767 | return SUCCESS; | |
768 | } | |
769 | ||
ae52e7f0 | 770 | static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
1c57e86d EC |
771 | { |
772 | struct Scsi_Host *host; | |
773 | struct AdapterControlBlock *acb; | |
cdd3cb15 | 774 | uint8_t bus,dev_fun; |
1c57e86d | 775 | int error; |
1c57e86d | 776 | error = pci_enable_device(pdev); |
cdd3cb15 | 777 | if(error){ |
ae52e7f0 NC |
778 | return -ENODEV; |
779 | } | |
780 | host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); | |
cdd3cb15 NC |
781 | if(!host){ |
782 | goto pci_disable_dev; | |
1c57e86d | 783 | } |
6a35528a | 784 | error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); |
cdd3cb15 | 785 | if(error){ |
284901a9 | 786 | error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
cdd3cb15 | 787 | if(error){ |
1c57e86d EC |
788 | printk(KERN_WARNING |
789 | "scsi%d: No suitable DMA mask available\n", | |
790 | host->host_no); | |
ae52e7f0 | 791 | goto scsi_host_release; |
1c57e86d EC |
792 | } |
793 | } | |
ae52e7f0 | 794 | init_waitqueue_head(&wait_q); |
1c57e86d EC |
795 | bus = pdev->bus->number; |
796 | dev_fun = pdev->devfn; | |
ae52e7f0 | 797 | acb = (struct AdapterControlBlock *) host->hostdata; |
cdd3cb15 | 798 | memset(acb,0,sizeof(struct AdapterControlBlock)); |
1c57e86d | 799 | acb->pdev = pdev; |
ae52e7f0 | 800 | acb->host = host; |
1c57e86d | 801 | host->max_lun = ARCMSR_MAX_TARGETLUN; |
cdd3cb15 NC |
802 | host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/ |
803 | host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/ | |
3df824af | 804 | host->can_queue = ARCMSR_MAX_OUTSTANDING_CMD; |
cdd3cb15 | 805 | host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; |
1c57e86d EC |
806 | host->this_id = ARCMSR_SCSI_INITIATOR_ID; |
807 | host->unique_id = (bus << 8) | dev_fun; | |
ae52e7f0 NC |
808 | pci_set_drvdata(pdev, host); |
809 | pci_set_master(pdev); | |
1c57e86d | 810 | error = pci_request_regions(pdev, "arcmsr"); |
cdd3cb15 | 811 | if(error){ |
ae52e7f0 | 812 | goto scsi_host_release; |
1c57e86d | 813 | } |
ae52e7f0 NC |
814 | spin_lock_init(&acb->eh_lock); |
815 | spin_lock_init(&acb->ccblist_lock); | |
5b37479a CH |
816 | spin_lock_init(&acb->postq_lock); |
817 | spin_lock_init(&acb->doneq_lock); | |
bb263c4e CH |
818 | spin_lock_init(&acb->rqbuffer_lock); |
819 | spin_lock_init(&acb->wqbuffer_lock); | |
1c57e86d | 820 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | |
cdd3cb15 NC |
821 | ACB_F_MESSAGE_RQBUFFER_CLEARED | |
822 | ACB_F_MESSAGE_WQBUFFER_READED); | |
1c57e86d EC |
823 | acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; |
824 | INIT_LIST_HEAD(&acb->ccb_free_list); | |
8b7c9942 | 825 | acb->adapter_type = id->driver_data; |
ae52e7f0 | 826 | error = arcmsr_remap_pciregion(acb); |
cdd3cb15 | 827 | if(!error){ |
ae52e7f0 NC |
828 | goto pci_release_regs; |
829 | } | |
02040670 CH |
830 | error = arcmsr_alloc_io_queue(acb); |
831 | if (!error) | |
832 | goto unmap_pci_region; | |
ae52e7f0 | 833 | error = arcmsr_get_firmware_spec(acb); |
cdd3cb15 | 834 | if(!error){ |
02040670 | 835 | goto free_hbb_mu; |
ae52e7f0 | 836 | } |
1c57e86d | 837 | error = arcmsr_alloc_ccb_pool(acb); |
cdd3cb15 | 838 | if(error){ |
ae52e7f0 NC |
839 | goto free_hbb_mu; |
840 | } | |
1c57e86d | 841 | error = scsi_add_host(host, &pdev->dev); |
cdd3cb15 | 842 | if(error){ |
b4eb6ae9 | 843 | goto free_ccb_pool; |
ae52e7f0 | 844 | } |
1d1166ea | 845 | if (arcmsr_request_irq(pdev, acb) == FAILED) |
ae52e7f0 | 846 | goto scsi_host_remove; |
1d1166ea | 847 | arcmsr_iop_init(acb); |
ae52e7f0 | 848 | INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); |
36b83ded | 849 | atomic_set(&acb->rq_map_token, 16); |
ae52e7f0 NC |
850 | atomic_set(&acb->ante_token_value, 16); |
851 | acb->fw_flag = FW_NORMAL; | |
36b83ded | 852 | init_timer(&acb->eternal_timer); |
ae52e7f0 | 853 | acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); |
36b83ded NC |
854 | acb->eternal_timer.data = (unsigned long) acb; |
855 | acb->eternal_timer.function = &arcmsr_request_device_map; | |
856 | add_timer(&acb->eternal_timer); | |
cdd3cb15 | 857 | if(arcmsr_alloc_sysfs_attr(acb)) |
ae52e7f0 | 858 | goto out_free_sysfs; |
b4eb6ae9 | 859 | scsi_scan_host(host); |
1c57e86d | 860 | return 0; |
cdd3cb15 | 861 | out_free_sysfs: |
b4eb6ae9 CH |
862 | del_timer_sync(&acb->eternal_timer); |
863 | flush_work(&acb->arcmsr_do_message_isr_bh); | |
ae52e7f0 NC |
864 | arcmsr_stop_adapter_bgrb(acb); |
865 | arcmsr_flush_adapter_cache(acb); | |
b4eb6ae9 CH |
866 | arcmsr_free_irq(pdev, acb); |
867 | scsi_host_remove: | |
868 | scsi_remove_host(host); | |
869 | free_ccb_pool: | |
1c57e86d | 870 | arcmsr_free_ccb_pool(acb); |
ae52e7f0 | 871 | free_hbb_mu: |
626fa32c | 872 | arcmsr_free_mu(acb); |
ae52e7f0 NC |
873 | unmap_pci_region: |
874 | arcmsr_unmap_pciregion(acb); | |
875 | pci_release_regs: | |
1c57e86d | 876 | pci_release_regions(pdev); |
ae52e7f0 | 877 | scsi_host_release: |
1c57e86d | 878 | scsi_host_put(host); |
ae52e7f0 | 879 | pci_disable_dev: |
1c57e86d | 880 | pci_disable_device(pdev); |
ae52e7f0 | 881 | return -ENODEV; |
1a4f550a NC |
882 | } |
883 | ||
1d1166ea CH |
884 | static void arcmsr_free_irq(struct pci_dev *pdev, |
885 | struct AdapterControlBlock *acb) | |
886 | { | |
887 | int i; | |
888 | ||
889 | if (acb->acb_flags & ACB_F_MSI_ENABLED) { | |
890 | free_irq(pdev->irq, acb); | |
891 | pci_disable_msi(pdev); | |
892 | } else if (acb->acb_flags & ACB_F_MSIX_ENABLED) { | |
893 | for (i = 0; i < acb->msix_vector_count; i++) | |
894 | free_irq(acb->entries[i].vector, acb); | |
895 | pci_disable_msix(pdev); | |
896 | } else | |
897 | free_irq(pdev->irq, acb); | |
898 | } | |
899 | ||
61cda87f CH |
900 | static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state) |
901 | { | |
902 | uint32_t intmask_org; | |
903 | struct Scsi_Host *host = pci_get_drvdata(pdev); | |
904 | struct AdapterControlBlock *acb = | |
905 | (struct AdapterControlBlock *)host->hostdata; | |
906 | ||
907 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
908 | arcmsr_free_irq(pdev, acb); | |
909 | del_timer_sync(&acb->eternal_timer); | |
910 | flush_work(&acb->arcmsr_do_message_isr_bh); | |
911 | arcmsr_stop_adapter_bgrb(acb); | |
912 | arcmsr_flush_adapter_cache(acb); | |
913 | pci_set_drvdata(pdev, host); | |
914 | pci_save_state(pdev); | |
915 | pci_disable_device(pdev); | |
916 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | |
917 | return 0; | |
918 | } | |
919 | ||
920 | static int arcmsr_resume(struct pci_dev *pdev) | |
921 | { | |
922 | int error; | |
923 | struct Scsi_Host *host = pci_get_drvdata(pdev); | |
924 | struct AdapterControlBlock *acb = | |
925 | (struct AdapterControlBlock *)host->hostdata; | |
926 | ||
927 | pci_set_power_state(pdev, PCI_D0); | |
928 | pci_enable_wake(pdev, PCI_D0, 0); | |
929 | pci_restore_state(pdev); | |
930 | if (pci_enable_device(pdev)) { | |
931 | pr_warn("%s: pci_enable_device error\n", __func__); | |
932 | return -ENODEV; | |
933 | } | |
934 | error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | |
935 | if (error) { | |
936 | error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | |
937 | if (error) { | |
938 | pr_warn("scsi%d: No suitable DMA mask available\n", | |
939 | host->host_no); | |
940 | goto controller_unregister; | |
941 | } | |
942 | } | |
943 | pci_set_master(pdev); | |
944 | if (arcmsr_request_irq(pdev, acb) == FAILED) | |
945 | goto controller_stop; | |
946 | arcmsr_iop_init(acb); | |
947 | INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); | |
948 | atomic_set(&acb->rq_map_token, 16); | |
949 | atomic_set(&acb->ante_token_value, 16); | |
950 | acb->fw_flag = FW_NORMAL; | |
951 | init_timer(&acb->eternal_timer); | |
952 | acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); | |
953 | acb->eternal_timer.data = (unsigned long) acb; | |
954 | acb->eternal_timer.function = &arcmsr_request_device_map; | |
955 | add_timer(&acb->eternal_timer); | |
956 | return 0; | |
957 | controller_stop: | |
958 | arcmsr_stop_adapter_bgrb(acb); | |
959 | arcmsr_flush_adapter_cache(acb); | |
960 | controller_unregister: | |
961 | scsi_remove_host(host); | |
962 | arcmsr_free_ccb_pool(acb); | |
963 | arcmsr_unmap_pciregion(acb); | |
964 | pci_release_regions(pdev); | |
965 | scsi_host_put(host); | |
966 | pci_disable_device(pdev); | |
967 | return -ENODEV; | |
968 | } | |
969 | ||
626fa32c | 970 | static uint8_t arcmsr_hbaA_abort_allcmd(struct AdapterControlBlock *acb) |
1c57e86d | 971 | { |
80da1adb | 972 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1c57e86d | 973 | writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); |
626fa32c | 974 | if (!arcmsr_hbaA_wait_msgint_ready(acb)) { |
1a4f550a | 975 | printk(KERN_NOTICE |
626fa32c | 976 | "arcmsr%d: wait 'abort all outstanding command' timeout\n" |
1a4f550a | 977 | , acb->host->host_no); |
cdd3cb15 | 978 | return false; |
36b83ded | 979 | } |
cdd3cb15 | 980 | return true; |
1a4f550a NC |
981 | } |
982 | ||
626fa32c | 983 | static uint8_t arcmsr_hbaB_abort_allcmd(struct AdapterControlBlock *acb) |
1a4f550a | 984 | { |
80da1adb | 985 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 986 | |
ae52e7f0 | 987 | writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); |
626fa32c | 988 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
1c57e86d | 989 | printk(KERN_NOTICE |
626fa32c | 990 | "arcmsr%d: wait 'abort all outstanding command' timeout\n" |
1c57e86d | 991 | , acb->host->host_no); |
cdd3cb15 | 992 | return false; |
36b83ded | 993 | } |
cdd3cb15 NC |
994 | return true; |
995 | } | |
626fa32c | 996 | static uint8_t arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB) |
cdd3cb15 | 997 | { |
c10b1d54 | 998 | struct MessageUnit_C __iomem *reg = pACB->pmuC; |
cdd3cb15 NC |
999 | writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); |
1000 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
626fa32c | 1001 | if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { |
cdd3cb15 | 1002 | printk(KERN_NOTICE |
626fa32c | 1003 | "arcmsr%d: wait 'abort all outstanding command' timeout\n" |
cdd3cb15 NC |
1004 | , pACB->host->host_no); |
1005 | return false; | |
1006 | } | |
1007 | return true; | |
1c57e86d | 1008 | } |
5b37479a CH |
1009 | |
1010 | static uint8_t arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB) | |
1011 | { | |
1012 | struct MessageUnit_D *reg = pACB->pmuD; | |
1013 | ||
1014 | writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, reg->inbound_msgaddr0); | |
1015 | if (!arcmsr_hbaD_wait_msgint_ready(pACB)) { | |
1016 | pr_notice("arcmsr%d: wait 'abort all outstanding " | |
1017 | "command' timeout\n", pACB->host->host_no); | |
1018 | return false; | |
1019 | } | |
1020 | return true; | |
1021 | } | |
1022 | ||
36b83ded | 1023 | static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) |
1a4f550a | 1024 | { |
36b83ded | 1025 | uint8_t rtnval = 0; |
1a4f550a NC |
1026 | switch (acb->adapter_type) { |
1027 | case ACB_ADAPTER_TYPE_A: { | |
626fa32c | 1028 | rtnval = arcmsr_hbaA_abort_allcmd(acb); |
1a4f550a NC |
1029 | } |
1030 | break; | |
1031 | ||
1032 | case ACB_ADAPTER_TYPE_B: { | |
626fa32c | 1033 | rtnval = arcmsr_hbaB_abort_allcmd(acb); |
1a4f550a | 1034 | } |
cdd3cb15 NC |
1035 | break; |
1036 | ||
1037 | case ACB_ADAPTER_TYPE_C: { | |
626fa32c | 1038 | rtnval = arcmsr_hbaC_abort_allcmd(acb); |
cdd3cb15 | 1039 | } |
5b37479a CH |
1040 | break; |
1041 | ||
1042 | case ACB_ADAPTER_TYPE_D: | |
1043 | rtnval = arcmsr_hbaD_abort_allcmd(acb); | |
1044 | break; | |
1a4f550a | 1045 | } |
36b83ded | 1046 | return rtnval; |
1a4f550a NC |
1047 | } |
1048 | ||
1c57e86d EC |
1049 | static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) |
1050 | { | |
1c57e86d EC |
1051 | struct scsi_cmnd *pcmd = ccb->pcmd; |
1052 | ||
deff2627 | 1053 | scsi_dma_unmap(pcmd); |
cdd3cb15 | 1054 | } |
1c57e86d | 1055 | |
ae52e7f0 | 1056 | static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) |
1c57e86d EC |
1057 | { |
1058 | struct AdapterControlBlock *acb = ccb->acb; | |
1059 | struct scsi_cmnd *pcmd = ccb->pcmd; | |
ae52e7f0 | 1060 | unsigned long flags; |
ae52e7f0 | 1061 | atomic_dec(&acb->ccboutstandingcount); |
1c57e86d | 1062 | arcmsr_pci_unmap_dma(ccb); |
1c57e86d | 1063 | ccb->startdone = ARCMSR_CCB_DONE; |
ae52e7f0 | 1064 | spin_lock_irqsave(&acb->ccblist_lock, flags); |
1c57e86d | 1065 | list_add_tail(&ccb->list, &acb->ccb_free_list); |
ae52e7f0 | 1066 | spin_unlock_irqrestore(&acb->ccblist_lock, flags); |
1c57e86d EC |
1067 | pcmd->scsi_done(pcmd); |
1068 | } | |
1069 | ||
1a4f550a NC |
1070 | static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) |
1071 | { | |
1072 | ||
1073 | struct scsi_cmnd *pcmd = ccb->pcmd; | |
1074 | struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; | |
1a4f550a NC |
1075 | pcmd->result = DID_OK << 16; |
1076 | if (sensebuffer) { | |
1077 | int sense_data_length = | |
b80ca4f7 FT |
1078 | sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE |
1079 | ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE; | |
1080 | memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE); | |
1a4f550a NC |
1081 | memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); |
1082 | sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; | |
1083 | sensebuffer->Valid = 1; | |
1084 | } | |
1085 | } | |
1086 | ||
1087 | static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) | |
1088 | { | |
1089 | u32 orig_mask = 0; | |
cdd3cb15 | 1090 | switch (acb->adapter_type) { |
1a4f550a | 1091 | case ACB_ADAPTER_TYPE_A : { |
80da1adb | 1092 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
36b83ded | 1093 | orig_mask = readl(®->outbound_intmask); |
1a4f550a NC |
1094 | writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ |
1095 | ®->outbound_intmask); | |
1096 | } | |
1097 | break; | |
1a4f550a | 1098 | case ACB_ADAPTER_TYPE_B : { |
80da1adb | 1099 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 NC |
1100 | orig_mask = readl(reg->iop2drv_doorbell_mask); |
1101 | writel(0, reg->iop2drv_doorbell_mask); | |
1a4f550a NC |
1102 | } |
1103 | break; | |
cdd3cb15 | 1104 | case ACB_ADAPTER_TYPE_C:{ |
c10b1d54 | 1105 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
1106 | /* disable all outbound interrupt */ |
1107 | orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */ | |
1108 | writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); | |
1109 | } | |
1110 | break; | |
5b37479a CH |
1111 | case ACB_ADAPTER_TYPE_D: { |
1112 | struct MessageUnit_D *reg = acb->pmuD; | |
1113 | /* disable all outbound interrupt */ | |
1114 | writel(ARCMSR_ARC1214_ALL_INT_DISABLE, reg->pcief0_int_enable); | |
1115 | } | |
1116 | break; | |
1a4f550a NC |
1117 | } |
1118 | return orig_mask; | |
1119 | } | |
1120 | ||
cdd3cb15 NC |
1121 | static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, |
1122 | struct CommandControlBlock *ccb, bool error) | |
1a4f550a | 1123 | { |
1a4f550a NC |
1124 | uint8_t id, lun; |
1125 | id = ccb->pcmd->device->id; | |
1126 | lun = ccb->pcmd->device->lun; | |
cdd3cb15 | 1127 | if (!error) { |
1a4f550a NC |
1128 | if (acb->devstate[id][lun] == ARECA_RAID_GONE) |
1129 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | |
7968f194 JL |
1130 | ccb->pcmd->result = DID_OK << 16; |
1131 | arcmsr_ccb_complete(ccb); | |
cdd3cb15 | 1132 | }else{ |
1a4f550a NC |
1133 | switch (ccb->arcmsr_cdb.DeviceStatus) { |
1134 | case ARCMSR_DEV_SELECT_TIMEOUT: { | |
1135 | acb->devstate[id][lun] = ARECA_RAID_GONE; | |
1136 | ccb->pcmd->result = DID_NO_CONNECT << 16; | |
ae52e7f0 | 1137 | arcmsr_ccb_complete(ccb); |
1a4f550a NC |
1138 | } |
1139 | break; | |
1140 | ||
1141 | case ARCMSR_DEV_ABORTED: | |
1142 | ||
1143 | case ARCMSR_DEV_INIT_FAIL: { | |
1144 | acb->devstate[id][lun] = ARECA_RAID_GONE; | |
1145 | ccb->pcmd->result = DID_BAD_TARGET << 16; | |
ae52e7f0 | 1146 | arcmsr_ccb_complete(ccb); |
1a4f550a NC |
1147 | } |
1148 | break; | |
1149 | ||
1150 | case ARCMSR_DEV_CHECK_CONDITION: { | |
1151 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | |
1152 | arcmsr_report_sense_info(ccb); | |
ae52e7f0 | 1153 | arcmsr_ccb_complete(ccb); |
1a4f550a NC |
1154 | } |
1155 | break; | |
1156 | ||
1157 | default: | |
cdd3cb15 NC |
1158 | printk(KERN_NOTICE |
1159 | "arcmsr%d: scsi id = %d lun = %d isr get command error done, \ | |
1160 | but got unknown DeviceStatus = 0x%x \n" | |
1161 | , acb->host->host_no | |
1162 | , id | |
1163 | , lun | |
1164 | , ccb->arcmsr_cdb.DeviceStatus); | |
1165 | acb->devstate[id][lun] = ARECA_RAID_GONE; | |
1166 | ccb->pcmd->result = DID_NO_CONNECT << 16; | |
1167 | arcmsr_ccb_complete(ccb); | |
1a4f550a NC |
1168 | break; |
1169 | } | |
1170 | } | |
1171 | } | |
1172 | ||
cdd3cb15 | 1173 | static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) |
1a4f550a | 1174 | { |
ae52e7f0 | 1175 | int id, lun; |
cdd3cb15 NC |
1176 | if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { |
1177 | if (pCCB->startdone == ARCMSR_CCB_ABORTED) { | |
1178 | struct scsi_cmnd *abortcmd = pCCB->pcmd; | |
1a4f550a | 1179 | if (abortcmd) { |
ae52e7f0 | 1180 | id = abortcmd->device->id; |
cdd3cb15 | 1181 | lun = abortcmd->device->lun; |
1a4f550a | 1182 | abortcmd->result |= DID_ABORT << 16; |
cdd3cb15 NC |
1183 | arcmsr_ccb_complete(pCCB); |
1184 | printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n", | |
1185 | acb->host->host_no, pCCB); | |
1a4f550a | 1186 | } |
cdd3cb15 | 1187 | return; |
1a4f550a NC |
1188 | } |
1189 | printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ | |
1190 | done acb = '0x%p'" | |
1191 | "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" | |
1192 | " ccboutstandingcount = %d \n" | |
1193 | , acb->host->host_no | |
1194 | , acb | |
cdd3cb15 NC |
1195 | , pCCB |
1196 | , pCCB->acb | |
1197 | , pCCB->startdone | |
1a4f550a | 1198 | , atomic_read(&acb->ccboutstandingcount)); |
cdd3cb15 | 1199 | return; |
97b99127 | 1200 | } |
cdd3cb15 | 1201 | arcmsr_report_ccb_state(acb, pCCB, error); |
1a4f550a NC |
1202 | } |
1203 | ||
1204 | static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) | |
1205 | { | |
1206 | int i = 0; | |
3b8155d5 | 1207 | uint32_t flag_ccb, ccb_cdb_phy; |
cdd3cb15 NC |
1208 | struct ARCMSR_CDB *pARCMSR_CDB; |
1209 | bool error; | |
1210 | struct CommandControlBlock *pCCB; | |
1a4f550a NC |
1211 | switch (acb->adapter_type) { |
1212 | ||
1213 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 1214 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a | 1215 | uint32_t outbound_intstatus; |
80da1adb | 1216 | outbound_intstatus = readl(®->outbound_intstatus) & |
1a4f550a NC |
1217 | acb->outbound_int_enable; |
1218 | /*clear and abort all outbound posted Q*/ | |
1219 | writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ | |
cdd3cb15 | 1220 | while(((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) |
1a4f550a | 1221 | && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { |
cdd3cb15 NC |
1222 | pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ |
1223 | pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | |
1224 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
1225 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1a4f550a NC |
1226 | } |
1227 | } | |
1228 | break; | |
1229 | ||
1230 | case ACB_ADAPTER_TYPE_B: { | |
80da1adb | 1231 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 1232 | /*clear all outbound posted Q*/ |
97b99127 | 1233 | writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */ |
1a4f550a | 1234 | for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { |
c10b1d54 CH |
1235 | flag_ccb = reg->done_qbuffer[i]; |
1236 | if (flag_ccb != 0) { | |
1237 | reg->done_qbuffer[i] = 0; | |
cdd3cb15 NC |
1238 | pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ |
1239 | pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | |
1240 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
1241 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1a4f550a | 1242 | } |
cdd3cb15 | 1243 | reg->post_qbuffer[i] = 0; |
1a4f550a NC |
1244 | } |
1245 | reg->doneq_index = 0; | |
1246 | reg->postq_index = 0; | |
1247 | } | |
1248 | break; | |
cdd3cb15 | 1249 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 1250 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
1251 | while ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { |
1252 | /*need to do*/ | |
1253 | flag_ccb = readl(®->outbound_queueport_low); | |
1254 | ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | |
1255 | pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/ | |
1256 | pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | |
1257 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; | |
1258 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1259 | } | |
5b37479a CH |
1260 | } |
1261 | break; | |
1262 | case ACB_ADAPTER_TYPE_D: { | |
1263 | struct MessageUnit_D *pmu = acb->pmuD; | |
3b8155d5 CH |
1264 | uint32_t outbound_write_pointer; |
1265 | uint32_t doneq_index, index_stripped, addressLow, residual, toggle; | |
1266 | unsigned long flags; | |
5b37479a | 1267 | |
5b37479a CH |
1268 | residual = atomic_read(&acb->ccboutstandingcount); |
1269 | for (i = 0; i < residual; i++) { | |
3b8155d5 CH |
1270 | spin_lock_irqsave(&acb->doneq_lock, flags); |
1271 | outbound_write_pointer = | |
1272 | pmu->done_qbuffer[0].addressLow + 1; | |
1273 | doneq_index = pmu->doneq_index; | |
1274 | if ((doneq_index & 0xFFF) != | |
5b37479a | 1275 | (outbound_write_pointer & 0xFFF)) { |
3b8155d5 CH |
1276 | toggle = doneq_index & 0x4000; |
1277 | index_stripped = (doneq_index & 0xFFF) + 1; | |
1278 | index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE; | |
1279 | pmu->doneq_index = index_stripped ? (index_stripped | toggle) : | |
1280 | ((toggle ^ 0x4000) + 1); | |
5b37479a | 1281 | doneq_index = pmu->doneq_index; |
3b8155d5 | 1282 | spin_unlock_irqrestore(&acb->doneq_lock, flags); |
5b37479a CH |
1283 | addressLow = pmu->done_qbuffer[doneq_index & |
1284 | 0xFFF].addressLow; | |
1285 | ccb_cdb_phy = (addressLow & 0xFFFFFFF0); | |
1286 | pARCMSR_CDB = (struct ARCMSR_CDB *) | |
1287 | (acb->vir2phy_offset + ccb_cdb_phy); | |
1288 | pCCB = container_of(pARCMSR_CDB, | |
1289 | struct CommandControlBlock, arcmsr_cdb); | |
1290 | error = (addressLow & | |
1291 | ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? | |
1292 | true : false; | |
1293 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1294 | writel(doneq_index, | |
1295 | pmu->outboundlist_read_pointer); | |
3b8155d5 CH |
1296 | } else { |
1297 | spin_unlock_irqrestore(&acb->doneq_lock, flags); | |
1298 | mdelay(10); | |
5b37479a | 1299 | } |
5b37479a CH |
1300 | } |
1301 | pmu->postq_index = 0; | |
1302 | pmu->doneq_index = 0x40FF; | |
1303 | } | |
1304 | break; | |
1a4f550a NC |
1305 | } |
1306 | } | |
1d1166ea | 1307 | |
1c57e86d EC |
1308 | static void arcmsr_remove(struct pci_dev *pdev) |
1309 | { | |
1310 | struct Scsi_Host *host = pci_get_drvdata(pdev); | |
1311 | struct AdapterControlBlock *acb = | |
1312 | (struct AdapterControlBlock *) host->hostdata; | |
1c57e86d | 1313 | int poll_count = 0; |
1c57e86d EC |
1314 | arcmsr_free_sysfs_attr(acb); |
1315 | scsi_remove_host(host); | |
43829731 | 1316 | flush_work(&acb->arcmsr_do_message_isr_bh); |
36b83ded NC |
1317 | del_timer_sync(&acb->eternal_timer); |
1318 | arcmsr_disable_outbound_ints(acb); | |
1c57e86d | 1319 | arcmsr_stop_adapter_bgrb(acb); |
cdd3cb15 | 1320 | arcmsr_flush_adapter_cache(acb); |
1c57e86d EC |
1321 | acb->acb_flags |= ACB_F_SCSISTOPADAPTER; |
1322 | acb->acb_flags &= ~ACB_F_IOP_INITED; | |
1323 | ||
cdd3cb15 | 1324 | for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){ |
1c57e86d EC |
1325 | if (!atomic_read(&acb->ccboutstandingcount)) |
1326 | break; | |
1a4f550a | 1327 | arcmsr_interrupt(acb);/* FIXME: need spinlock */ |
1c57e86d EC |
1328 | msleep(25); |
1329 | } | |
1330 | ||
1331 | if (atomic_read(&acb->ccboutstandingcount)) { | |
1332 | int i; | |
1333 | ||
1334 | arcmsr_abort_allcmd(acb); | |
1a4f550a | 1335 | arcmsr_done4abort_postqueue(acb); |
1c57e86d EC |
1336 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { |
1337 | struct CommandControlBlock *ccb = acb->pccb_pool[i]; | |
1338 | if (ccb->startdone == ARCMSR_CCB_START) { | |
1339 | ccb->startdone = ARCMSR_CCB_ABORTED; | |
1340 | ccb->pcmd->result = DID_ABORT << 16; | |
ae52e7f0 | 1341 | arcmsr_ccb_complete(ccb); |
1c57e86d EC |
1342 | } |
1343 | } | |
1344 | } | |
1d1166ea | 1345 | arcmsr_free_irq(pdev, acb); |
1c57e86d | 1346 | arcmsr_free_ccb_pool(acb); |
626fa32c | 1347 | arcmsr_free_mu(acb); |
cdd3cb15 | 1348 | arcmsr_unmap_pciregion(acb); |
1c57e86d | 1349 | pci_release_regions(pdev); |
cdd3cb15 | 1350 | scsi_host_put(host); |
1c57e86d | 1351 | pci_disable_device(pdev); |
1c57e86d EC |
1352 | } |
1353 | ||
1354 | static void arcmsr_shutdown(struct pci_dev *pdev) | |
1355 | { | |
1356 | struct Scsi_Host *host = pci_get_drvdata(pdev); | |
1357 | struct AdapterControlBlock *acb = | |
1358 | (struct AdapterControlBlock *)host->hostdata; | |
36b83ded NC |
1359 | del_timer_sync(&acb->eternal_timer); |
1360 | arcmsr_disable_outbound_ints(acb); | |
1d1166ea | 1361 | arcmsr_free_irq(pdev, acb); |
43829731 | 1362 | flush_work(&acb->arcmsr_do_message_isr_bh); |
1c57e86d EC |
1363 | arcmsr_stop_adapter_bgrb(acb); |
1364 | arcmsr_flush_adapter_cache(acb); | |
1365 | } | |
1366 | ||
1367 | static int arcmsr_module_init(void) | |
1368 | { | |
1369 | int error = 0; | |
1c57e86d EC |
1370 | error = pci_register_driver(&arcmsr_pci_driver); |
1371 | return error; | |
1372 | } | |
1373 | ||
1374 | static void arcmsr_module_exit(void) | |
1375 | { | |
1376 | pci_unregister_driver(&arcmsr_pci_driver); | |
1377 | } | |
1378 | module_init(arcmsr_module_init); | |
1379 | module_exit(arcmsr_module_exit); | |
1380 | ||
36b83ded | 1381 | static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, |
1a4f550a | 1382 | u32 intmask_org) |
1c57e86d | 1383 | { |
1c57e86d | 1384 | u32 mask; |
1a4f550a | 1385 | switch (acb->adapter_type) { |
1c57e86d | 1386 | |
cdd3cb15 | 1387 | case ACB_ADAPTER_TYPE_A: { |
80da1adb | 1388 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a | 1389 | mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | |
36b83ded NC |
1390 | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE| |
1391 | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); | |
1a4f550a NC |
1392 | writel(mask, ®->outbound_intmask); |
1393 | acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; | |
1394 | } | |
1395 | break; | |
1c57e86d | 1396 | |
cdd3cb15 | 1397 | case ACB_ADAPTER_TYPE_B: { |
80da1adb | 1398 | struct MessageUnit_B *reg = acb->pmuB; |
36b83ded NC |
1399 | mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | |
1400 | ARCMSR_IOP2DRV_DATA_READ_OK | | |
1401 | ARCMSR_IOP2DRV_CDB_DONE | | |
1402 | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); | |
ae52e7f0 | 1403 | writel(mask, reg->iop2drv_doorbell_mask); |
1a4f550a NC |
1404 | acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; |
1405 | } | |
cdd3cb15 NC |
1406 | break; |
1407 | case ACB_ADAPTER_TYPE_C: { | |
c10b1d54 | 1408 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
1409 | mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); |
1410 | writel(intmask_org & mask, ®->host_int_mask); | |
1411 | acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f; | |
1412 | } | |
5b37479a CH |
1413 | break; |
1414 | case ACB_ADAPTER_TYPE_D: { | |
1415 | struct MessageUnit_D *reg = acb->pmuD; | |
1416 | ||
1417 | mask = ARCMSR_ARC1214_ALL_INT_ENABLE; | |
1418 | writel(intmask_org | mask, reg->pcief0_int_enable); | |
1419 | break; | |
1420 | } | |
1c57e86d EC |
1421 | } |
1422 | } | |
1423 | ||
76d78300 | 1424 | static int arcmsr_build_ccb(struct AdapterControlBlock *acb, |
1a4f550a | 1425 | struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) |
1c57e86d | 1426 | { |
1a4f550a NC |
1427 | struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; |
1428 | int8_t *psge = (int8_t *)&arcmsr_cdb->u; | |
80da1adb | 1429 | __le32 address_lo, address_hi; |
1a4f550a | 1430 | int arccdbsize = 0x30; |
ae52e7f0 | 1431 | __le32 length = 0; |
cdd3cb15 | 1432 | int i; |
ae52e7f0 | 1433 | struct scatterlist *sg; |
1a4f550a | 1434 | int nseg; |
1c57e86d | 1435 | ccb->pcmd = pcmd; |
1a4f550a | 1436 | memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); |
1c57e86d EC |
1437 | arcmsr_cdb->TargetID = pcmd->device->id; |
1438 | arcmsr_cdb->LUN = pcmd->device->lun; | |
1439 | arcmsr_cdb->Function = 1; | |
626fa32c | 1440 | arcmsr_cdb->msgContext = 0; |
1c57e86d | 1441 | memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); |
deff2627 FT |
1442 | |
1443 | nseg = scsi_dma_map(pcmd); | |
cdd3cb15 | 1444 | if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0)) |
76d78300 | 1445 | return FAILED; |
cdd3cb15 NC |
1446 | scsi_for_each_sg(pcmd, sg, nseg, i) { |
1447 | /* Get the physical address of the current data pointer */ | |
1448 | length = cpu_to_le32(sg_dma_len(sg)); | |
1449 | address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); | |
1450 | address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); | |
1451 | if (address_hi == 0) { | |
1452 | struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; | |
1453 | ||
1454 | pdma_sg->address = address_lo; | |
1455 | pdma_sg->length = length; | |
1456 | psge += sizeof (struct SG32ENTRY); | |
1457 | arccdbsize += sizeof (struct SG32ENTRY); | |
1458 | } else { | |
1459 | struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; | |
1c57e86d | 1460 | |
cdd3cb15 NC |
1461 | pdma_sg->addresshigh = address_hi; |
1462 | pdma_sg->address = address_lo; | |
1463 | pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); | |
1464 | psge += sizeof (struct SG64ENTRY); | |
1465 | arccdbsize += sizeof (struct SG64ENTRY); | |
1c57e86d | 1466 | } |
cdd3cb15 NC |
1467 | } |
1468 | arcmsr_cdb->sgcount = (uint8_t)nseg; | |
1469 | arcmsr_cdb->DataLength = scsi_bufflen(pcmd); | |
ae52e7f0 | 1470 | arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0); |
cdd3cb15 NC |
1471 | if ( arccdbsize > 256) |
1472 | arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; | |
c32e061f | 1473 | if (pcmd->sc_data_direction == DMA_TO_DEVICE) |
1c57e86d | 1474 | arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; |
cdd3cb15 | 1475 | ccb->arc_cdb_size = arccdbsize; |
76d78300 | 1476 | return SUCCESS; |
1c57e86d EC |
1477 | } |
1478 | ||
1479 | static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) | |
1480 | { | |
626fa32c | 1481 | uint32_t cdb_phyaddr = ccb->cdb_phyaddr; |
1c57e86d | 1482 | struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; |
1c57e86d EC |
1483 | atomic_inc(&acb->ccboutstandingcount); |
1484 | ccb->startdone = ARCMSR_CCB_START; | |
1a4f550a NC |
1485 | switch (acb->adapter_type) { |
1486 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 1487 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
1488 | |
1489 | if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) | |
626fa32c | 1490 | writel(cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, |
1c57e86d | 1491 | ®->inbound_queueport); |
626fa32c CH |
1492 | else |
1493 | writel(cdb_phyaddr, ®->inbound_queueport); | |
1a4f550a | 1494 | break; |
626fa32c | 1495 | } |
1c57e86d | 1496 | |
1a4f550a | 1497 | case ACB_ADAPTER_TYPE_B: { |
80da1adb | 1498 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 1499 | uint32_t ending_index, index = reg->postq_index; |
1c57e86d | 1500 | |
1a4f550a | 1501 | ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); |
c10b1d54 | 1502 | reg->post_qbuffer[ending_index] = 0; |
1a4f550a | 1503 | if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { |
c10b1d54 CH |
1504 | reg->post_qbuffer[index] = |
1505 | cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE; | |
cdd3cb15 | 1506 | } else { |
c10b1d54 | 1507 | reg->post_qbuffer[index] = cdb_phyaddr; |
1a4f550a NC |
1508 | } |
1509 | index++; | |
1510 | index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ | |
1511 | reg->postq_index = index; | |
ae52e7f0 | 1512 | writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell); |
1c57e86d | 1513 | } |
1a4f550a | 1514 | break; |
cdd3cb15 | 1515 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 1516 | struct MessageUnit_C __iomem *phbcmu = acb->pmuC; |
cdd3cb15 NC |
1517 | uint32_t ccb_post_stamp, arc_cdb_size; |
1518 | ||
1519 | arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; | |
626fa32c | 1520 | ccb_post_stamp = (cdb_phyaddr | ((arc_cdb_size - 1) >> 6) | 1); |
cdd3cb15 NC |
1521 | if (acb->cdb_phyaddr_hi32) { |
1522 | writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); | |
1523 | writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); | |
1524 | } else { | |
1525 | writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); | |
1526 | } | |
1527 | } | |
5b37479a CH |
1528 | break; |
1529 | case ACB_ADAPTER_TYPE_D: { | |
1530 | struct MessageUnit_D *pmu = acb->pmuD; | |
1531 | u16 index_stripped; | |
3b8155d5 | 1532 | u16 postq_index, toggle; |
5b37479a CH |
1533 | unsigned long flags; |
1534 | struct InBound_SRB *pinbound_srb; | |
1535 | ||
1536 | spin_lock_irqsave(&acb->postq_lock, flags); | |
1537 | postq_index = pmu->postq_index; | |
1538 | pinbound_srb = (struct InBound_SRB *)&(pmu->post_qbuffer[postq_index & 0xFF]); | |
1539 | pinbound_srb->addressHigh = dma_addr_hi32(cdb_phyaddr); | |
1540 | pinbound_srb->addressLow = dma_addr_lo32(cdb_phyaddr); | |
1541 | pinbound_srb->length = ccb->arc_cdb_size >> 2; | |
1542 | arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr); | |
3b8155d5 CH |
1543 | toggle = postq_index & 0x4000; |
1544 | index_stripped = postq_index + 1; | |
1545 | index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1); | |
1546 | pmu->postq_index = index_stripped ? (index_stripped | toggle) : | |
1547 | (toggle ^ 0x4000); | |
5b37479a CH |
1548 | writel(postq_index, pmu->inboundlist_write_pointer); |
1549 | spin_unlock_irqrestore(&acb->postq_lock, flags); | |
1550 | break; | |
1551 | } | |
1c57e86d EC |
1552 | } |
1553 | } | |
1554 | ||
626fa32c | 1555 | static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb) |
1c57e86d | 1556 | { |
80da1adb | 1557 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1c57e86d EC |
1558 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; |
1559 | writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); | |
626fa32c | 1560 | if (!arcmsr_hbaA_wait_msgint_ready(acb)) { |
1a4f550a | 1561 | printk(KERN_NOTICE |
626fa32c | 1562 | "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" |
1a4f550a NC |
1563 | , acb->host->host_no); |
1564 | } | |
1565 | } | |
1566 | ||
626fa32c | 1567 | static void arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb) |
1a4f550a | 1568 | { |
80da1adb | 1569 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 1570 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; |
ae52e7f0 | 1571 | writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); |
1a4f550a | 1572 | |
626fa32c | 1573 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
1c57e86d | 1574 | printk(KERN_NOTICE |
626fa32c | 1575 | "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" |
1c57e86d | 1576 | , acb->host->host_no); |
1a4f550a NC |
1577 | } |
1578 | } | |
1579 | ||
626fa32c | 1580 | static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB) |
cdd3cb15 | 1581 | { |
c10b1d54 | 1582 | struct MessageUnit_C __iomem *reg = pACB->pmuC; |
cdd3cb15 NC |
1583 | pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; |
1584 | writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); | |
1585 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
626fa32c | 1586 | if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { |
cdd3cb15 | 1587 | printk(KERN_NOTICE |
626fa32c | 1588 | "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" |
cdd3cb15 NC |
1589 | , pACB->host->host_no); |
1590 | } | |
1591 | return; | |
1592 | } | |
5b37479a CH |
1593 | |
1594 | static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB) | |
1595 | { | |
1596 | struct MessageUnit_D *reg = pACB->pmuD; | |
1597 | ||
1598 | pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; | |
1599 | writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, reg->inbound_msgaddr0); | |
1600 | if (!arcmsr_hbaD_wait_msgint_ready(pACB)) | |
1601 | pr_notice("arcmsr%d: wait 'stop adapter background rebulid' " | |
1602 | "timeout\n", pACB->host->host_no); | |
1603 | } | |
1604 | ||
1a4f550a NC |
1605 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) |
1606 | { | |
1607 | switch (acb->adapter_type) { | |
1608 | case ACB_ADAPTER_TYPE_A: { | |
626fa32c | 1609 | arcmsr_hbaA_stop_bgrb(acb); |
1a4f550a NC |
1610 | } |
1611 | break; | |
1612 | ||
1613 | case ACB_ADAPTER_TYPE_B: { | |
626fa32c | 1614 | arcmsr_hbaB_stop_bgrb(acb); |
1a4f550a NC |
1615 | } |
1616 | break; | |
cdd3cb15 | 1617 | case ACB_ADAPTER_TYPE_C: { |
626fa32c | 1618 | arcmsr_hbaC_stop_bgrb(acb); |
cdd3cb15 | 1619 | } |
5b37479a CH |
1620 | break; |
1621 | case ACB_ADAPTER_TYPE_D: | |
1622 | arcmsr_hbaD_stop_bgrb(acb); | |
1623 | break; | |
1a4f550a | 1624 | } |
1c57e86d EC |
1625 | } |
1626 | ||
1627 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) | |
1628 | { | |
cdd3cb15 | 1629 | dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); |
1c57e86d EC |
1630 | } |
1631 | ||
c10b1d54 | 1632 | static void arcmsr_iop_message_read(struct AdapterControlBlock *acb) |
1c57e86d | 1633 | { |
1a4f550a NC |
1634 | switch (acb->adapter_type) { |
1635 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 1636 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
1637 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); |
1638 | } | |
1639 | break; | |
1c57e86d | 1640 | |
1a4f550a | 1641 | case ACB_ADAPTER_TYPE_B: { |
80da1adb | 1642 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 | 1643 | writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); |
1c57e86d | 1644 | } |
1a4f550a | 1645 | break; |
cdd3cb15 NC |
1646 | case ACB_ADAPTER_TYPE_C: { |
1647 | struct MessageUnit_C __iomem *reg = acb->pmuC; | |
5b37479a | 1648 | |
cdd3cb15 NC |
1649 | writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); |
1650 | } | |
5b37479a CH |
1651 | break; |
1652 | case ACB_ADAPTER_TYPE_D: { | |
1653 | struct MessageUnit_D *reg = acb->pmuD; | |
1654 | writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ, | |
1655 | reg->inbound_doorbell); | |
1656 | } | |
1657 | break; | |
1c57e86d | 1658 | } |
1a4f550a NC |
1659 | } |
1660 | ||
1661 | static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) | |
1662 | { | |
1663 | switch (acb->adapter_type) { | |
1664 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 1665 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1c57e86d | 1666 | /* |
1a4f550a NC |
1667 | ** push inbound doorbell tell iop, driver data write ok |
1668 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
1c57e86d | 1669 | */ |
1a4f550a NC |
1670 | writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); |
1671 | } | |
1672 | break; | |
1673 | ||
1674 | case ACB_ADAPTER_TYPE_B: { | |
80da1adb | 1675 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a NC |
1676 | /* |
1677 | ** push inbound doorbell tell iop, driver data write ok | |
1678 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
1679 | */ | |
ae52e7f0 | 1680 | writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell); |
1a4f550a NC |
1681 | } |
1682 | break; | |
cdd3cb15 NC |
1683 | case ACB_ADAPTER_TYPE_C: { |
1684 | struct MessageUnit_C __iomem *reg = acb->pmuC; | |
1685 | /* | |
1686 | ** push inbound doorbell tell iop, driver data write ok | |
1687 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
1688 | */ | |
1689 | writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell); | |
1690 | } | |
1691 | break; | |
5b37479a CH |
1692 | case ACB_ADAPTER_TYPE_D: { |
1693 | struct MessageUnit_D *reg = acb->pmuD; | |
1694 | writel(ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY, | |
1695 | reg->inbound_doorbell); | |
1696 | } | |
1697 | break; | |
1a4f550a NC |
1698 | } |
1699 | } | |
1700 | ||
80da1adb | 1701 | struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) |
1a4f550a | 1702 | { |
0c7eb2eb | 1703 | struct QBUFFER __iomem *qbuffer = NULL; |
1a4f550a NC |
1704 | switch (acb->adapter_type) { |
1705 | ||
1706 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb AV |
1707 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1708 | qbuffer = (struct QBUFFER __iomem *)®->message_rbuffer; | |
1a4f550a NC |
1709 | } |
1710 | break; | |
1711 | ||
1712 | case ACB_ADAPTER_TYPE_B: { | |
80da1adb | 1713 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 | 1714 | qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; |
1a4f550a NC |
1715 | } |
1716 | break; | |
cdd3cb15 | 1717 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 1718 | struct MessageUnit_C __iomem *phbcmu = acb->pmuC; |
cdd3cb15 NC |
1719 | qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer; |
1720 | } | |
5b37479a CH |
1721 | break; |
1722 | case ACB_ADAPTER_TYPE_D: { | |
1723 | struct MessageUnit_D *reg = acb->pmuD; | |
1724 | qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; | |
1725 | } | |
1726 | break; | |
1a4f550a NC |
1727 | } |
1728 | return qbuffer; | |
1729 | } | |
1730 | ||
80da1adb | 1731 | static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) |
1a4f550a | 1732 | { |
0c7eb2eb | 1733 | struct QBUFFER __iomem *pqbuffer = NULL; |
1a4f550a NC |
1734 | switch (acb->adapter_type) { |
1735 | ||
1736 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb AV |
1737 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1738 | pqbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; | |
1a4f550a NC |
1739 | } |
1740 | break; | |
1741 | ||
1742 | case ACB_ADAPTER_TYPE_B: { | |
80da1adb | 1743 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 | 1744 | pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; |
1a4f550a NC |
1745 | } |
1746 | break; | |
cdd3cb15 | 1747 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 1748 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 | 1749 | pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer; |
5b37479a CH |
1750 | } |
1751 | break; | |
1752 | case ACB_ADAPTER_TYPE_D: { | |
1753 | struct MessageUnit_D *reg = acb->pmuD; | |
1754 | pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; | |
1755 | } | |
1756 | break; | |
1a4f550a NC |
1757 | } |
1758 | return pqbuffer; | |
1759 | } | |
1760 | ||
bb263c4e CH |
1761 | static uint32_t |
1762 | arcmsr_Read_iop_rqbuffer_in_DWORD(struct AdapterControlBlock *acb, | |
1763 | struct QBUFFER __iomem *prbuffer) | |
1a4f550a | 1764 | { |
bb263c4e CH |
1765 | uint8_t *pQbuffer; |
1766 | uint8_t *buf1 = NULL; | |
1767 | uint32_t __iomem *iop_data; | |
1768 | uint32_t iop_len, data_len, *buf2 = NULL; | |
1769 | ||
1770 | iop_data = (uint32_t __iomem *)prbuffer->data; | |
1771 | iop_len = readl(&prbuffer->data_len); | |
1772 | if (iop_len > 0) { | |
1773 | buf1 = kmalloc(128, GFP_ATOMIC); | |
1774 | buf2 = (uint32_t *)buf1; | |
1775 | if (buf1 == NULL) | |
1776 | return 0; | |
1777 | data_len = iop_len; | |
1778 | while (data_len >= 4) { | |
1779 | *buf2++ = readl(iop_data); | |
1a4f550a | 1780 | iop_data++; |
bb263c4e | 1781 | data_len -= 4; |
1a4f550a | 1782 | } |
bb263c4e CH |
1783 | if (data_len) |
1784 | *buf2 = readl(iop_data); | |
1785 | buf2 = (uint32_t *)buf1; | |
1786 | } | |
1787 | while (iop_len > 0) { | |
2e9feb43 | 1788 | pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex]; |
bb263c4e | 1789 | *pQbuffer = *buf1; |
2e9feb43 | 1790 | acb->rqbuf_putIndex++; |
bb263c4e | 1791 | /* if last, index number set it to 0 */ |
2e9feb43 | 1792 | acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER; |
bb263c4e CH |
1793 | buf1++; |
1794 | iop_len--; | |
1795 | } | |
2e9feb43 | 1796 | kfree(buf2); |
bb263c4e CH |
1797 | /* let IOP know data has been read */ |
1798 | arcmsr_iop_message_read(acb); | |
1799 | return 1; | |
1800 | } | |
1801 | ||
1802 | uint32_t | |
1803 | arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, | |
1804 | struct QBUFFER __iomem *prbuffer) { | |
1805 | ||
1806 | uint8_t *pQbuffer; | |
1807 | uint8_t __iomem *iop_data; | |
1808 | uint32_t iop_len; | |
1809 | ||
5b37479a | 1810 | if (acb->adapter_type & (ACB_ADAPTER_TYPE_C | ACB_ADAPTER_TYPE_D)) |
bb263c4e CH |
1811 | return arcmsr_Read_iop_rqbuffer_in_DWORD(acb, prbuffer); |
1812 | iop_data = (uint8_t __iomem *)prbuffer->data; | |
1813 | iop_len = readl(&prbuffer->data_len); | |
1814 | while (iop_len > 0) { | |
2e9feb43 | 1815 | pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex]; |
bb263c4e | 1816 | *pQbuffer = readb(iop_data); |
2e9feb43 CH |
1817 | acb->rqbuf_putIndex++; |
1818 | acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER; | |
bb263c4e CH |
1819 | iop_data++; |
1820 | iop_len--; | |
1a4f550a | 1821 | } |
bb263c4e CH |
1822 | arcmsr_iop_message_read(acb); |
1823 | return 1; | |
1824 | } | |
1a4f550a | 1825 | |
bb263c4e CH |
1826 | static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) |
1827 | { | |
1828 | unsigned long flags; | |
1829 | struct QBUFFER __iomem *prbuffer; | |
1830 | int32_t buf_empty_len; | |
1831 | ||
1832 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); | |
1833 | prbuffer = arcmsr_get_iop_rqbuffer(acb); | |
2e9feb43 | 1834 | buf_empty_len = (acb->rqbuf_putIndex - acb->rqbuf_getIndex - 1) & |
bb263c4e CH |
1835 | (ARCMSR_MAX_QBUFFER - 1); |
1836 | if (buf_empty_len >= readl(&prbuffer->data_len)) { | |
1837 | if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) | |
1838 | acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; | |
1839 | } else | |
1a4f550a | 1840 | acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; |
bb263c4e CH |
1841 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); |
1842 | } | |
1843 | ||
1844 | static void arcmsr_write_ioctldata2iop_in_DWORD(struct AdapterControlBlock *acb) | |
1845 | { | |
1846 | uint8_t *pQbuffer; | |
1847 | struct QBUFFER __iomem *pwbuffer; | |
1848 | uint8_t *buf1 = NULL; | |
1849 | uint32_t __iomem *iop_data; | |
1850 | uint32_t allxfer_len = 0, data_len, *buf2 = NULL, data; | |
1851 | ||
1852 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { | |
1853 | buf1 = kmalloc(128, GFP_ATOMIC); | |
1854 | buf2 = (uint32_t *)buf1; | |
1855 | if (buf1 == NULL) | |
1856 | return; | |
1857 | ||
1858 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); | |
1859 | pwbuffer = arcmsr_get_iop_wqbuffer(acb); | |
1860 | iop_data = (uint32_t __iomem *)pwbuffer->data; | |
2e9feb43 | 1861 | while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex) |
bb263c4e | 1862 | && (allxfer_len < 124)) { |
2e9feb43 | 1863 | pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex]; |
bb263c4e | 1864 | *buf1 = *pQbuffer; |
2e9feb43 CH |
1865 | acb->wqbuf_getIndex++; |
1866 | acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER; | |
bb263c4e CH |
1867 | buf1++; |
1868 | allxfer_len++; | |
1869 | } | |
1870 | data_len = allxfer_len; | |
1871 | buf1 = (uint8_t *)buf2; | |
1872 | while (data_len >= 4) { | |
1873 | data = *buf2++; | |
1874 | writel(data, iop_data); | |
1875 | iop_data++; | |
1876 | data_len -= 4; | |
1877 | } | |
1878 | if (data_len) { | |
1879 | data = *buf2; | |
1880 | writel(data, iop_data); | |
1881 | } | |
1882 | writel(allxfer_len, &pwbuffer->data_len); | |
1883 | kfree(buf1); | |
1884 | arcmsr_iop_message_wrote(acb); | |
1a4f550a NC |
1885 | } |
1886 | } | |
1887 | ||
bb263c4e CH |
1888 | void |
1889 | arcmsr_write_ioctldata2iop(struct AdapterControlBlock *acb) | |
1a4f550a | 1890 | { |
bb263c4e CH |
1891 | uint8_t *pQbuffer; |
1892 | struct QBUFFER __iomem *pwbuffer; | |
1893 | uint8_t __iomem *iop_data; | |
1894 | int32_t allxfer_len = 0; | |
1a4f550a | 1895 | |
5b37479a | 1896 | if (acb->adapter_type & (ACB_ADAPTER_TYPE_C | ACB_ADAPTER_TYPE_D)) { |
bb263c4e CH |
1897 | arcmsr_write_ioctldata2iop_in_DWORD(acb); |
1898 | return; | |
1899 | } | |
1900 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { | |
1a4f550a NC |
1901 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); |
1902 | pwbuffer = arcmsr_get_iop_wqbuffer(acb); | |
1903 | iop_data = (uint8_t __iomem *)pwbuffer->data; | |
2e9feb43 | 1904 | while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex) |
bb263c4e | 1905 | && (allxfer_len < 124)) { |
2e9feb43 | 1906 | pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex]; |
bb263c4e | 1907 | writeb(*pQbuffer, iop_data); |
2e9feb43 CH |
1908 | acb->wqbuf_getIndex++; |
1909 | acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER; | |
1a4f550a NC |
1910 | iop_data++; |
1911 | allxfer_len++; | |
1912 | } | |
bb263c4e | 1913 | writel(allxfer_len, &pwbuffer->data_len); |
1a4f550a NC |
1914 | arcmsr_iop_message_wrote(acb); |
1915 | } | |
bb263c4e | 1916 | } |
1a4f550a | 1917 | |
bb263c4e CH |
1918 | static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) |
1919 | { | |
1920 | unsigned long flags; | |
1921 | ||
1922 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); | |
1923 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; | |
2e9feb43 | 1924 | if (acb->wqbuf_getIndex != acb->wqbuf_putIndex) |
bb263c4e | 1925 | arcmsr_write_ioctldata2iop(acb); |
2e9feb43 | 1926 | if (acb->wqbuf_getIndex == acb->wqbuf_putIndex) |
1a4f550a | 1927 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; |
bb263c4e | 1928 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); |
1a4f550a NC |
1929 | } |
1930 | ||
626fa32c | 1931 | static void arcmsr_hbaA_doorbell_isr(struct AdapterControlBlock *acb) |
1a4f550a NC |
1932 | { |
1933 | uint32_t outbound_doorbell; | |
80da1adb | 1934 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a | 1935 | outbound_doorbell = readl(®->outbound_doorbell); |
6b393722 CH |
1936 | do { |
1937 | writel(outbound_doorbell, ®->outbound_doorbell); | |
1938 | if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) | |
1939 | arcmsr_iop2drv_data_wrote_handle(acb); | |
1940 | if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) | |
1941 | arcmsr_iop2drv_data_read_handle(acb); | |
1942 | outbound_doorbell = readl(®->outbound_doorbell); | |
1943 | } while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK | |
1944 | | ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)); | |
1a4f550a | 1945 | } |
626fa32c | 1946 | static void arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB) |
cdd3cb15 NC |
1947 | { |
1948 | uint32_t outbound_doorbell; | |
c10b1d54 | 1949 | struct MessageUnit_C __iomem *reg = pACB->pmuC; |
cdd3cb15 NC |
1950 | /* |
1951 | ******************************************************************* | |
1952 | ** Maybe here we need to check wrqbuffer_lock is lock or not | |
1953 | ** DOORBELL: din! don! | |
1954 | ** check if there are any mail need to pack from firmware | |
1955 | ******************************************************************* | |
1956 | */ | |
1957 | outbound_doorbell = readl(®->outbound_doorbell); | |
6b393722 CH |
1958 | do { |
1959 | writel(outbound_doorbell, ®->outbound_doorbell_clear); | |
1960 | readl(®->outbound_doorbell_clear); | |
1961 | if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) | |
1962 | arcmsr_iop2drv_data_wrote_handle(pACB); | |
1963 | if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) | |
1964 | arcmsr_iop2drv_data_read_handle(pACB); | |
1965 | if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) | |
626fa32c | 1966 | arcmsr_hbaC_message_isr(pACB); |
6b393722 CH |
1967 | outbound_doorbell = readl(®->outbound_doorbell); |
1968 | } while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK | |
1969 | | ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK | |
1970 | | ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)); | |
cdd3cb15 | 1971 | } |
5b37479a CH |
1972 | |
1973 | static void arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB) | |
1974 | { | |
1975 | uint32_t outbound_doorbell; | |
1976 | struct MessageUnit_D *pmu = pACB->pmuD; | |
1977 | ||
1978 | outbound_doorbell = readl(pmu->outbound_doorbell); | |
1979 | do { | |
1980 | writel(outbound_doorbell, pmu->outbound_doorbell); | |
1981 | if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) | |
1982 | arcmsr_hbaD_message_isr(pACB); | |
1983 | if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK) | |
1984 | arcmsr_iop2drv_data_wrote_handle(pACB); | |
1985 | if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK) | |
1986 | arcmsr_iop2drv_data_read_handle(pACB); | |
1987 | outbound_doorbell = readl(pmu->outbound_doorbell); | |
1988 | } while (outbound_doorbell & (ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK | |
1989 | | ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK | |
1990 | | ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE)); | |
1991 | } | |
1992 | ||
626fa32c | 1993 | static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb) |
1a4f550a NC |
1994 | { |
1995 | uint32_t flag_ccb; | |
80da1adb | 1996 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
cdd3cb15 NC |
1997 | struct ARCMSR_CDB *pARCMSR_CDB; |
1998 | struct CommandControlBlock *pCCB; | |
1999 | bool error; | |
1a4f550a | 2000 | while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { |
cdd3cb15 NC |
2001 | pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ |
2002 | pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | |
2003 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
2004 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1a4f550a NC |
2005 | } |
2006 | } | |
626fa32c | 2007 | static void arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb) |
1a4f550a NC |
2008 | { |
2009 | uint32_t index; | |
2010 | uint32_t flag_ccb; | |
80da1adb | 2011 | struct MessageUnit_B *reg = acb->pmuB; |
cdd3cb15 NC |
2012 | struct ARCMSR_CDB *pARCMSR_CDB; |
2013 | struct CommandControlBlock *pCCB; | |
2014 | bool error; | |
1a4f550a | 2015 | index = reg->doneq_index; |
c10b1d54 CH |
2016 | while ((flag_ccb = reg->done_qbuffer[index]) != 0) { |
2017 | reg->done_qbuffer[index] = 0; | |
cdd3cb15 NC |
2018 | pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ |
2019 | pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | |
2020 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
2021 | arcmsr_drain_donequeue(acb, pCCB, error); | |
1a4f550a NC |
2022 | index++; |
2023 | index %= ARCMSR_MAX_HBB_POSTQUEUE; | |
2024 | reg->doneq_index = index; | |
2025 | } | |
2026 | } | |
cdd3cb15 | 2027 | |
626fa32c | 2028 | static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb) |
cdd3cb15 | 2029 | { |
c10b1d54 | 2030 | struct MessageUnit_C __iomem *phbcmu; |
cdd3cb15 NC |
2031 | struct ARCMSR_CDB *arcmsr_cdb; |
2032 | struct CommandControlBlock *ccb; | |
2033 | uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; | |
2034 | int error; | |
2035 | ||
c10b1d54 | 2036 | phbcmu = acb->pmuC; |
cdd3cb15 NC |
2037 | /* areca cdb command done */ |
2038 | /* Use correct offset and size for syncing */ | |
2039 | ||
6b393722 CH |
2040 | while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) != |
2041 | 0xFFFFFFFF) { | |
2042 | ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | |
2043 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset | |
2044 | + ccb_cdb_phy); | |
2045 | ccb = container_of(arcmsr_cdb, struct CommandControlBlock, | |
2046 | arcmsr_cdb); | |
2047 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) | |
2048 | ? true : false; | |
2049 | /* check if command done with no error */ | |
2050 | arcmsr_drain_donequeue(acb, ccb, error); | |
2051 | throttling++; | |
2052 | if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { | |
2053 | writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, | |
2054 | &phbcmu->inbound_doorbell); | |
2055 | throttling = 0; | |
2056 | } | |
cdd3cb15 NC |
2057 | } |
2058 | } | |
5b37479a CH |
2059 | |
2060 | static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb) | |
2061 | { | |
3b8155d5 | 2062 | u32 outbound_write_pointer, doneq_index, index_stripped, toggle; |
5b37479a CH |
2063 | uint32_t addressLow, ccb_cdb_phy; |
2064 | int error; | |
2065 | struct MessageUnit_D *pmu; | |
2066 | struct ARCMSR_CDB *arcmsr_cdb; | |
2067 | struct CommandControlBlock *ccb; | |
2068 | unsigned long flags; | |
2069 | ||
2070 | spin_lock_irqsave(&acb->doneq_lock, flags); | |
2071 | pmu = acb->pmuD; | |
2072 | outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1; | |
2073 | doneq_index = pmu->doneq_index; | |
2074 | if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) { | |
2075 | do { | |
3b8155d5 CH |
2076 | toggle = doneq_index & 0x4000; |
2077 | index_stripped = (doneq_index & 0xFFF) + 1; | |
2078 | index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE; | |
2079 | pmu->doneq_index = index_stripped ? (index_stripped | toggle) : | |
2080 | ((toggle ^ 0x4000) + 1); | |
5b37479a CH |
2081 | doneq_index = pmu->doneq_index; |
2082 | addressLow = pmu->done_qbuffer[doneq_index & | |
2083 | 0xFFF].addressLow; | |
2084 | ccb_cdb_phy = (addressLow & 0xFFFFFFF0); | |
2085 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset | |
2086 | + ccb_cdb_phy); | |
2087 | ccb = container_of(arcmsr_cdb, | |
2088 | struct CommandControlBlock, arcmsr_cdb); | |
2089 | error = (addressLow & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) | |
2090 | ? true : false; | |
2091 | arcmsr_drain_donequeue(acb, ccb, error); | |
2092 | writel(doneq_index, pmu->outboundlist_read_pointer); | |
2093 | } while ((doneq_index & 0xFFF) != | |
2094 | (outbound_write_pointer & 0xFFF)); | |
2095 | } | |
2096 | writel(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR, | |
2097 | pmu->outboundlist_interrupt_cause); | |
2098 | readl(pmu->outboundlist_interrupt_cause); | |
2099 | spin_unlock_irqrestore(&acb->doneq_lock, flags); | |
2100 | } | |
2101 | ||
36b83ded NC |
2102 | /* |
2103 | ********************************************************************************** | |
2104 | ** Handle a message interrupt | |
2105 | ** | |
cdd3cb15 | 2106 | ** The only message interrupt we expect is in response to a query for the current adapter config. |
36b83ded NC |
2107 | ** We want this in order to compare the drivemap so that we can detect newly-attached drives. |
2108 | ********************************************************************************** | |
2109 | */ | |
626fa32c | 2110 | static void arcmsr_hbaA_message_isr(struct AdapterControlBlock *acb) |
36b83ded | 2111 | { |
c10b1d54 | 2112 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
36b83ded NC |
2113 | /*clear interrupt and message state*/ |
2114 | writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); | |
2115 | schedule_work(&acb->arcmsr_do_message_isr_bh); | |
2116 | } | |
626fa32c | 2117 | static void arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb) |
36b83ded NC |
2118 | { |
2119 | struct MessageUnit_B *reg = acb->pmuB; | |
1a4f550a | 2120 | |
36b83ded | 2121 | /*clear interrupt and message state*/ |
ae52e7f0 | 2122 | writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); |
36b83ded NC |
2123 | schedule_work(&acb->arcmsr_do_message_isr_bh); |
2124 | } | |
cdd3cb15 NC |
2125 | /* |
2126 | ********************************************************************************** | |
2127 | ** Handle a message interrupt | |
2128 | ** | |
2129 | ** The only message interrupt we expect is in response to a query for the | |
2130 | ** current adapter config. | |
2131 | ** We want this in order to compare the drivemap so that we can detect newly-attached drives. | |
2132 | ********************************************************************************** | |
2133 | */ | |
626fa32c | 2134 | static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *acb) |
cdd3cb15 | 2135 | { |
c10b1d54 | 2136 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
2137 | /*clear interrupt and message state*/ |
2138 | writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear); | |
2139 | schedule_work(&acb->arcmsr_do_message_isr_bh); | |
2140 | } | |
2141 | ||
5b37479a CH |
2142 | static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb) |
2143 | { | |
2144 | struct MessageUnit_D *reg = acb->pmuD; | |
2145 | ||
2146 | writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE, reg->outbound_doorbell); | |
2147 | readl(reg->outbound_doorbell); | |
2148 | schedule_work(&acb->arcmsr_do_message_isr_bh); | |
2149 | } | |
2150 | ||
626fa32c | 2151 | static int arcmsr_hbaA_handle_isr(struct AdapterControlBlock *acb) |
1a4f550a NC |
2152 | { |
2153 | uint32_t outbound_intstatus; | |
80da1adb | 2154 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
36b83ded | 2155 | outbound_intstatus = readl(®->outbound_intstatus) & |
cdd3cb15 | 2156 | acb->outbound_int_enable; |
6b393722 CH |
2157 | if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) |
2158 | return IRQ_NONE; | |
2159 | do { | |
2160 | writel(outbound_intstatus, ®->outbound_intstatus); | |
2161 | if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) | |
626fa32c | 2162 | arcmsr_hbaA_doorbell_isr(acb); |
6b393722 | 2163 | if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) |
626fa32c | 2164 | arcmsr_hbaA_postqueue_isr(acb); |
6b393722 | 2165 | if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) |
626fa32c | 2166 | arcmsr_hbaA_message_isr(acb); |
6b393722 CH |
2167 | outbound_intstatus = readl(®->outbound_intstatus) & |
2168 | acb->outbound_int_enable; | |
2169 | } while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT | |
2170 | | ARCMSR_MU_OUTBOUND_POSTQUEUE_INT | |
2171 | | ARCMSR_MU_OUTBOUND_MESSAGE0_INT)); | |
2172 | return IRQ_HANDLED; | |
1a4f550a NC |
2173 | } |
2174 | ||
626fa32c | 2175 | static int arcmsr_hbaB_handle_isr(struct AdapterControlBlock *acb) |
1a4f550a NC |
2176 | { |
2177 | uint32_t outbound_doorbell; | |
80da1adb | 2178 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 | 2179 | outbound_doorbell = readl(reg->iop2drv_doorbell) & |
cdd3cb15 | 2180 | acb->outbound_int_enable; |
1a4f550a | 2181 | if (!outbound_doorbell) |
6b393722 CH |
2182 | return IRQ_NONE; |
2183 | do { | |
2184 | writel(~outbound_doorbell, reg->iop2drv_doorbell); | |
2185 | writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); | |
2186 | if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) | |
2187 | arcmsr_iop2drv_data_wrote_handle(acb); | |
2188 | if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) | |
2189 | arcmsr_iop2drv_data_read_handle(acb); | |
2190 | if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) | |
626fa32c | 2191 | arcmsr_hbaB_postqueue_isr(acb); |
6b393722 | 2192 | if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) |
626fa32c | 2193 | arcmsr_hbaB_message_isr(acb); |
6b393722 CH |
2194 | outbound_doorbell = readl(reg->iop2drv_doorbell) & |
2195 | acb->outbound_int_enable; | |
2196 | } while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK | |
2197 | | ARCMSR_IOP2DRV_DATA_READ_OK | |
2198 | | ARCMSR_IOP2DRV_CDB_DONE | |
2199 | | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)); | |
2200 | return IRQ_HANDLED; | |
1a4f550a NC |
2201 | } |
2202 | ||
626fa32c | 2203 | static int arcmsr_hbaC_handle_isr(struct AdapterControlBlock *pACB) |
cdd3cb15 NC |
2204 | { |
2205 | uint32_t host_interrupt_status; | |
c10b1d54 | 2206 | struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; |
cdd3cb15 NC |
2207 | /* |
2208 | ********************************************* | |
2209 | ** check outbound intstatus | |
2210 | ********************************************* | |
2211 | */ | |
6b393722 CH |
2212 | host_interrupt_status = readl(&phbcmu->host_int_status) & |
2213 | (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR | | |
2214 | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR); | |
2215 | if (!host_interrupt_status) | |
2216 | return IRQ_NONE; | |
2217 | do { | |
2218 | if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) | |
626fa32c | 2219 | arcmsr_hbaC_doorbell_isr(pACB); |
6b393722 CH |
2220 | /* MU post queue interrupts*/ |
2221 | if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) | |
626fa32c | 2222 | arcmsr_hbaC_postqueue_isr(pACB); |
6b393722 CH |
2223 | host_interrupt_status = readl(&phbcmu->host_int_status); |
2224 | } while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR | | |
2225 | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR)); | |
2226 | return IRQ_HANDLED; | |
cdd3cb15 | 2227 | } |
5b37479a CH |
2228 | |
2229 | static irqreturn_t arcmsr_hbaD_handle_isr(struct AdapterControlBlock *pACB) | |
2230 | { | |
2231 | u32 host_interrupt_status; | |
2232 | struct MessageUnit_D *pmu = pACB->pmuD; | |
2233 | ||
2234 | host_interrupt_status = readl(pmu->host_int_status) & | |
2235 | (ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR | | |
2236 | ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR); | |
2237 | if (!host_interrupt_status) | |
2238 | return IRQ_NONE; | |
2239 | do { | |
2240 | /* MU post queue interrupts*/ | |
2241 | if (host_interrupt_status & | |
2242 | ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR) | |
2243 | arcmsr_hbaD_postqueue_isr(pACB); | |
2244 | if (host_interrupt_status & | |
2245 | ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR) | |
2246 | arcmsr_hbaD_doorbell_isr(pACB); | |
2247 | host_interrupt_status = readl(pmu->host_int_status); | |
2248 | } while (host_interrupt_status & | |
2249 | (ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR | | |
2250 | ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR)); | |
2251 | return IRQ_HANDLED; | |
2252 | } | |
2253 | ||
1a4f550a NC |
2254 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) |
2255 | { | |
2256 | switch (acb->adapter_type) { | |
6b393722 | 2257 | case ACB_ADAPTER_TYPE_A: |
626fa32c | 2258 | return arcmsr_hbaA_handle_isr(acb); |
1a4f550a | 2259 | break; |
6b393722 | 2260 | case ACB_ADAPTER_TYPE_B: |
626fa32c | 2261 | return arcmsr_hbaB_handle_isr(acb); |
1a4f550a | 2262 | break; |
6b393722 | 2263 | case ACB_ADAPTER_TYPE_C: |
626fa32c | 2264 | return arcmsr_hbaC_handle_isr(acb); |
5b37479a CH |
2265 | case ACB_ADAPTER_TYPE_D: |
2266 | return arcmsr_hbaD_handle_isr(acb); | |
6b393722 CH |
2267 | default: |
2268 | return IRQ_NONE; | |
1c57e86d | 2269 | } |
1c57e86d EC |
2270 | } |
2271 | ||
2272 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) | |
2273 | { | |
2274 | if (acb) { | |
2275 | /* stop adapter background rebuild */ | |
2276 | if (acb->acb_flags & ACB_F_MSG_START_BGRB) { | |
1a4f550a | 2277 | uint32_t intmask_org; |
1c57e86d | 2278 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; |
1a4f550a | 2279 | intmask_org = arcmsr_disable_outbound_ints(acb); |
1c57e86d EC |
2280 | arcmsr_stop_adapter_bgrb(acb); |
2281 | arcmsr_flush_adapter_cache(acb); | |
1a4f550a NC |
2282 | arcmsr_enable_outbound_ints(acb, intmask_org); |
2283 | } | |
2284 | } | |
2285 | } | |
2286 | ||
bb263c4e CH |
2287 | |
2288 | void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *acb) | |
1a4f550a | 2289 | { |
bb263c4e CH |
2290 | uint32_t i; |
2291 | ||
2292 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
2293 | for (i = 0; i < 15; i++) { | |
2294 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
2295 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
2e9feb43 CH |
2296 | acb->rqbuf_getIndex = 0; |
2297 | acb->rqbuf_putIndex = 0; | |
bb263c4e CH |
2298 | arcmsr_iop_message_read(acb); |
2299 | mdelay(30); | |
2e9feb43 CH |
2300 | } else if (acb->rqbuf_getIndex != |
2301 | acb->rqbuf_putIndex) { | |
2302 | acb->rqbuf_getIndex = 0; | |
2303 | acb->rqbuf_putIndex = 0; | |
bb263c4e CH |
2304 | mdelay(30); |
2305 | } else | |
2306 | break; | |
1c57e86d EC |
2307 | } |
2308 | } | |
2309 | } | |
2310 | ||
36b83ded | 2311 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, |
bb263c4e | 2312 | struct scsi_cmnd *cmd) |
1c57e86d | 2313 | { |
1c57e86d | 2314 | char *buffer; |
bb263c4e CH |
2315 | unsigned short use_sg; |
2316 | int retvalue = 0, transfer_len = 0; | |
2317 | unsigned long flags; | |
2318 | struct CMD_MESSAGE_FIELD *pcmdmessagefld; | |
2319 | uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 | | |
2320 | (uint32_t)cmd->cmnd[6] << 16 | | |
2321 | (uint32_t)cmd->cmnd[7] << 8 | | |
2322 | (uint32_t)cmd->cmnd[8]; | |
deff2627 | 2323 | struct scatterlist *sg; |
bb263c4e CH |
2324 | |
2325 | use_sg = scsi_sg_count(cmd); | |
deff2627 | 2326 | sg = scsi_sglist(cmd); |
77dfce07 | 2327 | buffer = kmap_atomic(sg_page(sg)) + sg->offset; |
bb263c4e | 2328 | if (use_sg > 1) { |
deff2627 FT |
2329 | retvalue = ARCMSR_MESSAGE_FAIL; |
2330 | goto message_out; | |
1c57e86d | 2331 | } |
deff2627 | 2332 | transfer_len += sg->length; |
1c57e86d EC |
2333 | if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { |
2334 | retvalue = ARCMSR_MESSAGE_FAIL; | |
bb263c4e | 2335 | pr_info("%s: ARCMSR_MESSAGE_FAIL!\n", __func__); |
1c57e86d EC |
2336 | goto message_out; |
2337 | } | |
bb263c4e CH |
2338 | pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer; |
2339 | switch (controlcode) { | |
1c57e86d | 2340 | case ARCMSR_MESSAGE_READ_RQBUFFER: { |
69e562c2 | 2341 | unsigned char *ver_addr; |
2e9feb43 | 2342 | uint8_t *ptmpQbuffer; |
bb263c4e | 2343 | uint32_t allxfer_len = 0; |
2e9feb43 | 2344 | ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); |
69e562c2 | 2345 | if (!ver_addr) { |
1a4f550a | 2346 | retvalue = ARCMSR_MESSAGE_FAIL; |
bb263c4e | 2347 | pr_info("%s: memory not enough!\n", __func__); |
1a4f550a NC |
2348 | goto message_out; |
2349 | } | |
69e562c2 | 2350 | ptmpQbuffer = ver_addr; |
bb263c4e | 2351 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); |
2e9feb43 CH |
2352 | if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) { |
2353 | unsigned int tail = acb->rqbuf_getIndex; | |
2354 | unsigned int head = acb->rqbuf_putIndex; | |
2355 | unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER); | |
2356 | ||
2357 | allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER); | |
2358 | if (allxfer_len > ARCMSR_API_DATA_BUFLEN) | |
2359 | allxfer_len = ARCMSR_API_DATA_BUFLEN; | |
2360 | ||
2361 | if (allxfer_len <= cnt_to_end) | |
2362 | memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len); | |
2363 | else { | |
2364 | memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end); | |
2365 | memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end); | |
bb263c4e | 2366 | } |
2e9feb43 | 2367 | acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER; |
1a4f550a | 2368 | } |
bb263c4e CH |
2369 | memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, |
2370 | allxfer_len); | |
1a4f550a | 2371 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { |
80da1adb | 2372 | struct QBUFFER __iomem *prbuffer; |
1a4f550a NC |
2373 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; |
2374 | prbuffer = arcmsr_get_iop_rqbuffer(acb); | |
bb263c4e CH |
2375 | if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) |
2376 | acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; | |
ae52e7f0 | 2377 | } |
bb263c4e | 2378 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); |
69e562c2 | 2379 | kfree(ver_addr); |
bb263c4e CH |
2380 | pcmdmessagefld->cmdmessage.Length = allxfer_len; |
2381 | if (acb->fw_flag == FW_DEADLOCK) | |
2382 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2383 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | |
2384 | else | |
2385 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2386 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
1c57e86d | 2387 | break; |
bb263c4e | 2388 | } |
1a4f550a | 2389 | case ARCMSR_MESSAGE_WRITE_WQBUFFER: { |
69e562c2 | 2390 | unsigned char *ver_addr; |
7bc2b55a DC |
2391 | uint32_t user_len; |
2392 | int32_t cnt2end; | |
1a4f550a | 2393 | uint8_t *pQbuffer, *ptmpuserbuffer; |
4bd173c3 BP |
2394 | |
2395 | user_len = pcmdmessagefld->cmdmessage.Length; | |
2396 | if (user_len > ARCMSR_API_DATA_BUFLEN) { | |
1a4f550a NC |
2397 | retvalue = ARCMSR_MESSAGE_FAIL; |
2398 | goto message_out; | |
2399 | } | |
4bd173c3 BP |
2400 | |
2401 | ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); | |
2402 | if (!ver_addr) { | |
7bc2b55a | 2403 | retvalue = ARCMSR_MESSAGE_FAIL; |
7bc2b55a DC |
2404 | goto message_out; |
2405 | } | |
4bd173c3 BP |
2406 | ptmpuserbuffer = ver_addr; |
2407 | ||
bb263c4e CH |
2408 | memcpy(ptmpuserbuffer, |
2409 | pcmdmessagefld->messagedatabuffer, user_len); | |
2410 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); | |
2e9feb43 | 2411 | if (acb->wqbuf_putIndex != acb->wqbuf_getIndex) { |
1a4f550a NC |
2412 | struct SENSE_DATA *sensebuffer = |
2413 | (struct SENSE_DATA *)cmd->sense_buffer; | |
bb263c4e | 2414 | arcmsr_write_ioctldata2iop(acb); |
1a4f550a | 2415 | /* has error report sensedata */ |
bb263c4e | 2416 | sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; |
1a4f550a NC |
2417 | sensebuffer->SenseKey = ILLEGAL_REQUEST; |
2418 | sensebuffer->AdditionalSenseLength = 0x0A; | |
2419 | sensebuffer->AdditionalSenseCode = 0x20; | |
2420 | sensebuffer->Valid = 1; | |
2421 | retvalue = ARCMSR_MESSAGE_FAIL; | |
2422 | } else { | |
2e9feb43 CH |
2423 | pQbuffer = &acb->wqbuffer[acb->wqbuf_putIndex]; |
2424 | cnt2end = ARCMSR_MAX_QBUFFER - acb->wqbuf_putIndex; | |
2425 | if (user_len > cnt2end) { | |
2426 | memcpy(pQbuffer, ptmpuserbuffer, cnt2end); | |
2427 | ptmpuserbuffer += cnt2end; | |
2428 | user_len -= cnt2end; | |
2429 | acb->wqbuf_putIndex = 0; | |
2430 | pQbuffer = acb->wqbuffer; | |
2431 | } | |
2432 | memcpy(pQbuffer, ptmpuserbuffer, user_len); | |
2433 | acb->wqbuf_putIndex += user_len; | |
2434 | acb->wqbuf_putIndex %= ARCMSR_MAX_QBUFFER; | |
2435 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | |
2436 | acb->acb_flags &= | |
1a4f550a | 2437 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; |
2e9feb43 | 2438 | arcmsr_write_ioctldata2iop(acb); |
1a4f550a | 2439 | } |
1c57e86d | 2440 | } |
bb263c4e CH |
2441 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); |
2442 | kfree(ver_addr); | |
2443 | if (acb->fw_flag == FW_DEADLOCK) | |
2444 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2445 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | |
2446 | else | |
2447 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2448 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
1c57e86d | 2449 | break; |
bb263c4e | 2450 | } |
1c57e86d | 2451 | case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { |
1a4f550a | 2452 | uint8_t *pQbuffer = acb->rqbuffer; |
bb263c4e CH |
2453 | |
2454 | arcmsr_clear_iop2drv_rqueue_buffer(acb); | |
2455 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); | |
1a4f550a | 2456 | acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; |
2e9feb43 CH |
2457 | acb->rqbuf_getIndex = 0; |
2458 | acb->rqbuf_putIndex = 0; | |
1a4f550a | 2459 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); |
bb263c4e CH |
2460 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); |
2461 | if (acb->fw_flag == FW_DEADLOCK) | |
ae52e7f0 | 2462 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2463 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2464 | else | |
ae52e7f0 | 2465 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e | 2466 | ARCMSR_MESSAGE_RETURNCODE_OK; |
1c57e86d | 2467 | break; |
bb263c4e | 2468 | } |
1c57e86d | 2469 | case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { |
1a4f550a | 2470 | uint8_t *pQbuffer = acb->wqbuffer; |
bb263c4e CH |
2471 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); |
2472 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | | |
2473 | ACB_F_MESSAGE_WQBUFFER_READED); | |
2e9feb43 CH |
2474 | acb->wqbuf_getIndex = 0; |
2475 | acb->wqbuf_putIndex = 0; | |
1a4f550a | 2476 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); |
bb263c4e CH |
2477 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); |
2478 | if (acb->fw_flag == FW_DEADLOCK) | |
2479 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2480 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | |
2481 | else | |
2482 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2483 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
1c57e86d | 2484 | break; |
bb263c4e | 2485 | } |
1c57e86d | 2486 | case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { |
1a4f550a | 2487 | uint8_t *pQbuffer; |
bb263c4e CH |
2488 | arcmsr_clear_iop2drv_rqueue_buffer(acb); |
2489 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); | |
2490 | acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; | |
2e9feb43 CH |
2491 | acb->rqbuf_getIndex = 0; |
2492 | acb->rqbuf_putIndex = 0; | |
1a4f550a NC |
2493 | pQbuffer = acb->rqbuffer; |
2494 | memset(pQbuffer, 0, sizeof(struct QBUFFER)); | |
bb263c4e CH |
2495 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); |
2496 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); | |
2497 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | | |
2498 | ACB_F_MESSAGE_WQBUFFER_READED); | |
2e9feb43 CH |
2499 | acb->wqbuf_getIndex = 0; |
2500 | acb->wqbuf_putIndex = 0; | |
1a4f550a NC |
2501 | pQbuffer = acb->wqbuffer; |
2502 | memset(pQbuffer, 0, sizeof(struct QBUFFER)); | |
bb263c4e CH |
2503 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); |
2504 | if (acb->fw_flag == FW_DEADLOCK) | |
ae52e7f0 | 2505 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2506 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2507 | else | |
ae52e7f0 | 2508 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e | 2509 | ARCMSR_MESSAGE_RETURNCODE_OK; |
1c57e86d | 2510 | break; |
bb263c4e | 2511 | } |
1c57e86d | 2512 | case ARCMSR_MESSAGE_RETURN_CODE_3F: { |
bb263c4e | 2513 | if (acb->fw_flag == FW_DEADLOCK) |
36b83ded | 2514 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2515 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2516 | else | |
ae52e7f0 | 2517 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e | 2518 | ARCMSR_MESSAGE_RETURNCODE_3F; |
1c57e86d | 2519 | break; |
bb263c4e | 2520 | } |
1c57e86d | 2521 | case ARCMSR_MESSAGE_SAY_HELLO: { |
1a4f550a | 2522 | int8_t *hello_string = "Hello! I am ARCMSR"; |
bb263c4e | 2523 | if (acb->fw_flag == FW_DEADLOCK) |
36b83ded | 2524 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2525 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2526 | else | |
ae52e7f0 | 2527 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2528 | ARCMSR_MESSAGE_RETURNCODE_OK; |
2529 | memcpy(pcmdmessagefld->messagedatabuffer, | |
2530 | hello_string, (int16_t)strlen(hello_string)); | |
1c57e86d | 2531 | break; |
bb263c4e CH |
2532 | } |
2533 | case ARCMSR_MESSAGE_SAY_GOODBYE: { | |
2534 | if (acb->fw_flag == FW_DEADLOCK) | |
36b83ded | 2535 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2536 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2537 | else | |
2538 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2539 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
1c57e86d EC |
2540 | arcmsr_iop_parking(acb); |
2541 | break; | |
bb263c4e CH |
2542 | } |
2543 | case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: { | |
2544 | if (acb->fw_flag == FW_DEADLOCK) | |
36b83ded | 2545 | pcmdmessagefld->cmdmessage.ReturnCode = |
bb263c4e CH |
2546 | ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; |
2547 | else | |
2548 | pcmdmessagefld->cmdmessage.ReturnCode = | |
2549 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
1c57e86d EC |
2550 | arcmsr_flush_adapter_cache(acb); |
2551 | break; | |
bb263c4e | 2552 | } |
1c57e86d EC |
2553 | default: |
2554 | retvalue = ARCMSR_MESSAGE_FAIL; | |
bb263c4e CH |
2555 | pr_info("%s: unknown controlcode!\n", __func__); |
2556 | } | |
2557 | message_out: | |
2558 | if (use_sg) { | |
2559 | struct scatterlist *sg = scsi_sglist(cmd); | |
2560 | kunmap_atomic(buffer - sg->offset); | |
1c57e86d | 2561 | } |
1c57e86d EC |
2562 | return retvalue; |
2563 | } | |
2564 | ||
2565 | static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb) | |
2566 | { | |
2567 | struct list_head *head = &acb->ccb_free_list; | |
2568 | struct CommandControlBlock *ccb = NULL; | |
ae52e7f0 NC |
2569 | unsigned long flags; |
2570 | spin_lock_irqsave(&acb->ccblist_lock, flags); | |
1c57e86d EC |
2571 | if (!list_empty(head)) { |
2572 | ccb = list_entry(head->next, struct CommandControlBlock, list); | |
ae52e7f0 | 2573 | list_del_init(&ccb->list); |
cdd3cb15 | 2574 | }else{ |
ae52e7f0 | 2575 | spin_unlock_irqrestore(&acb->ccblist_lock, flags); |
c10b1d54 | 2576 | return NULL; |
1c57e86d | 2577 | } |
ae52e7f0 | 2578 | spin_unlock_irqrestore(&acb->ccblist_lock, flags); |
1c57e86d EC |
2579 | return ccb; |
2580 | } | |
2581 | ||
2582 | static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, | |
2583 | struct scsi_cmnd *cmd) | |
2584 | { | |
2585 | switch (cmd->cmnd[0]) { | |
2586 | case INQUIRY: { | |
2587 | unsigned char inqdata[36]; | |
2588 | char *buffer; | |
deff2627 | 2589 | struct scatterlist *sg; |
1c57e86d EC |
2590 | |
2591 | if (cmd->device->lun) { | |
2592 | cmd->result = (DID_TIME_OUT << 16); | |
2593 | cmd->scsi_done(cmd); | |
2594 | return; | |
2595 | } | |
2596 | inqdata[0] = TYPE_PROCESSOR; | |
2597 | /* Periph Qualifier & Periph Dev Type */ | |
2598 | inqdata[1] = 0; | |
2599 | /* rem media bit & Dev Type Modifier */ | |
2600 | inqdata[2] = 0; | |
a1f6e021 | 2601 | /* ISO, ECMA, & ANSI versions */ |
1c57e86d EC |
2602 | inqdata[4] = 31; |
2603 | /* length of additional data */ | |
2604 | strncpy(&inqdata[8], "Areca ", 8); | |
2605 | /* Vendor Identification */ | |
2606 | strncpy(&inqdata[16], "RAID controller ", 16); | |
2607 | /* Product Identification */ | |
2608 | strncpy(&inqdata[32], "R001", 4); /* Product Revision */ | |
1c57e86d | 2609 | |
deff2627 | 2610 | sg = scsi_sglist(cmd); |
77dfce07 | 2611 | buffer = kmap_atomic(sg_page(sg)) + sg->offset; |
deff2627 | 2612 | |
1c57e86d | 2613 | memcpy(buffer, inqdata, sizeof(inqdata)); |
deff2627 | 2614 | sg = scsi_sglist(cmd); |
77dfce07 | 2615 | kunmap_atomic(buffer - sg->offset); |
1c57e86d | 2616 | |
1c57e86d EC |
2617 | cmd->scsi_done(cmd); |
2618 | } | |
2619 | break; | |
2620 | case WRITE_BUFFER: | |
2621 | case READ_BUFFER: { | |
2622 | if (arcmsr_iop_message_xfer(acb, cmd)) | |
2623 | cmd->result = (DID_ERROR << 16); | |
2624 | cmd->scsi_done(cmd); | |
2625 | } | |
2626 | break; | |
2627 | default: | |
2628 | cmd->scsi_done(cmd); | |
2629 | } | |
2630 | } | |
2631 | ||
f281233d | 2632 | static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, |
1c57e86d EC |
2633 | void (* done)(struct scsi_cmnd *)) |
2634 | { | |
2635 | struct Scsi_Host *host = cmd->device->host; | |
1a4f550a | 2636 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; |
1c57e86d EC |
2637 | struct CommandControlBlock *ccb; |
2638 | int target = cmd->device->id; | |
2639 | int lun = cmd->device->lun; | |
36b83ded | 2640 | uint8_t scsicmd = cmd->cmnd[0]; |
1c57e86d EC |
2641 | cmd->scsi_done = done; |
2642 | cmd->host_scribble = NULL; | |
2643 | cmd->result = 0; | |
cdd3cb15 NC |
2644 | if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){ |
2645 | if(acb->devstate[target][lun] == ARECA_RAID_GONE) { | |
2646 | cmd->result = (DID_NO_CONNECT << 16); | |
36b83ded NC |
2647 | } |
2648 | cmd->scsi_done(cmd); | |
2649 | return 0; | |
2650 | } | |
a1f6e021 | 2651 | if (target == 16) { |
1c57e86d EC |
2652 | /* virtual device for iop message transfer */ |
2653 | arcmsr_handle_virtual_command(acb, cmd); | |
2654 | return 0; | |
2655 | } | |
1c57e86d EC |
2656 | ccb = arcmsr_get_freeccb(acb); |
2657 | if (!ccb) | |
2658 | return SCSI_MLQUEUE_HOST_BUSY; | |
cdd3cb15 | 2659 | if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) { |
76d78300 NC |
2660 | cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); |
2661 | cmd->scsi_done(cmd); | |
2662 | return 0; | |
2663 | } | |
1c57e86d EC |
2664 | arcmsr_post_ccb(acb, ccb); |
2665 | return 0; | |
2666 | } | |
2667 | ||
f281233d JG |
2668 | static DEF_SCSI_QCMD(arcmsr_queue_command) |
2669 | ||
626fa32c | 2670 | static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb) |
1c57e86d | 2671 | { |
80da1adb | 2672 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1c57e86d EC |
2673 | char *acb_firm_model = acb->firm_model; |
2674 | char *acb_firm_version = acb->firm_version; | |
36b83ded | 2675 | char *acb_device_map = acb->device_map; |
80da1adb AV |
2676 | char __iomem *iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); |
2677 | char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); | |
cdd3cb15 | 2678 | char __iomem *iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); |
1c57e86d | 2679 | int count; |
1c57e86d | 2680 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); |
626fa32c | 2681 | if (!arcmsr_hbaA_wait_msgint_ready(acb)) { |
1a4f550a NC |
2682 | printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ |
2683 | miscellaneous data' timeout \n", acb->host->host_no); | |
ae52e7f0 | 2684 | return false; |
1a4f550a | 2685 | } |
1c57e86d | 2686 | count = 8; |
cdd3cb15 | 2687 | while (count){ |
1c57e86d EC |
2688 | *acb_firm_model = readb(iop_firm_model); |
2689 | acb_firm_model++; | |
2690 | iop_firm_model++; | |
2691 | count--; | |
2692 | } | |
1a4f550a | 2693 | |
1c57e86d | 2694 | count = 16; |
cdd3cb15 | 2695 | while (count){ |
1c57e86d EC |
2696 | *acb_firm_version = readb(iop_firm_version); |
2697 | acb_firm_version++; | |
2698 | iop_firm_version++; | |
2699 | count--; | |
2700 | } | |
1a4f550a | 2701 | |
cdd3cb15 NC |
2702 | count=16; |
2703 | while(count){ | |
2704 | *acb_device_map = readb(iop_device_map); | |
2705 | acb_device_map++; | |
2706 | iop_device_map++; | |
2707 | count--; | |
2708 | } | |
a2c89bbc | 2709 | pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", |
ae52e7f0 | 2710 | acb->host->host_no, |
a2c89bbc CH |
2711 | acb->firm_model, |
2712 | acb->firm_version); | |
cdd3cb15 | 2713 | acb->signature = readl(®->message_rwbuffer[0]); |
1c57e86d EC |
2714 | acb->firm_request_len = readl(®->message_rwbuffer[1]); |
2715 | acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); | |
2716 | acb->firm_sdram_size = readl(®->message_rwbuffer[3]); | |
2717 | acb->firm_hd_channels = readl(®->message_rwbuffer[4]); | |
ae52e7f0 NC |
2718 | acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ |
2719 | return true; | |
1c57e86d | 2720 | } |
626fa32c | 2721 | static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb) |
1a4f550a | 2722 | { |
02040670 | 2723 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a NC |
2724 | char *acb_firm_model = acb->firm_model; |
2725 | char *acb_firm_version = acb->firm_version; | |
36b83ded | 2726 | char *acb_device_map = acb->device_map; |
ae52e7f0 | 2727 | char __iomem *iop_firm_model; |
1a4f550a | 2728 | /*firm_model,15,60-67*/ |
ae52e7f0 | 2729 | char __iomem *iop_firm_version; |
1a4f550a | 2730 | /*firm_version,17,68-83*/ |
ae52e7f0 | 2731 | char __iomem *iop_device_map; |
36b83ded | 2732 | /*firm_version,21,84-99*/ |
1a4f550a | 2733 | int count; |
6e38adfc | 2734 | |
ae52e7f0 NC |
2735 | iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); /*firm_model,15,60-67*/ |
2736 | iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); /*firm_version,17,68-83*/ | |
2737 | iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); /*firm_version,21,84-99*/ | |
2738 | ||
7e315ffd CH |
2739 | arcmsr_wait_firmware_ready(acb); |
2740 | writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); | |
2741 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { | |
2742 | printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no); | |
02040670 | 2743 | return false; |
7e315ffd | 2744 | } |
ae52e7f0 | 2745 | writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); |
626fa32c | 2746 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
1a4f550a NC |
2747 | printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ |
2748 | miscellaneous data' timeout \n", acb->host->host_no); | |
02040670 | 2749 | return false; |
1a4f550a | 2750 | } |
1a4f550a | 2751 | count = 8; |
cdd3cb15 | 2752 | while (count){ |
1a4f550a NC |
2753 | *acb_firm_model = readb(iop_firm_model); |
2754 | acb_firm_model++; | |
2755 | iop_firm_model++; | |
2756 | count--; | |
2757 | } | |
1a4f550a | 2758 | count = 16; |
cdd3cb15 | 2759 | while (count){ |
1a4f550a NC |
2760 | *acb_firm_version = readb(iop_firm_version); |
2761 | acb_firm_version++; | |
2762 | iop_firm_version++; | |
2763 | count--; | |
2764 | } | |
2765 | ||
cdd3cb15 NC |
2766 | count = 16; |
2767 | while(count){ | |
2768 | *acb_device_map = readb(iop_device_map); | |
2769 | acb_device_map++; | |
2770 | iop_device_map++; | |
2771 | count--; | |
2772 | } | |
2773 | ||
a2c89bbc | 2774 | pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", |
cdd3cb15 | 2775 | acb->host->host_no, |
a2c89bbc CH |
2776 | acb->firm_model, |
2777 | acb->firm_version); | |
1a4f550a | 2778 | |
251e2d25 | 2779 | acb->signature = readl(®->message_rwbuffer[0]); |
cdd3cb15 | 2780 | /*firm_signature,1,00-03*/ |
251e2d25 | 2781 | acb->firm_request_len = readl(®->message_rwbuffer[1]); |
1a4f550a | 2782 | /*firm_request_len,1,04-07*/ |
251e2d25 | 2783 | acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); |
1a4f550a | 2784 | /*firm_numbers_queue,2,08-11*/ |
251e2d25 | 2785 | acb->firm_sdram_size = readl(®->message_rwbuffer[3]); |
1a4f550a | 2786 | /*firm_sdram_size,3,12-15*/ |
251e2d25 | 2787 | acb->firm_hd_channels = readl(®->message_rwbuffer[4]); |
1a4f550a | 2788 | /*firm_ide_channels,4,16-19*/ |
ae52e7f0 NC |
2789 | acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ |
2790 | /*firm_ide_channels,4,16-19*/ | |
2791 | return true; | |
1a4f550a | 2792 | } |
cdd3cb15 | 2793 | |
626fa32c | 2794 | static bool arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB) |
cdd3cb15 NC |
2795 | { |
2796 | uint32_t intmask_org, Index, firmware_state = 0; | |
c10b1d54 | 2797 | struct MessageUnit_C __iomem *reg = pACB->pmuC; |
cdd3cb15 NC |
2798 | char *acb_firm_model = pACB->firm_model; |
2799 | char *acb_firm_version = pACB->firm_version; | |
c10b1d54 CH |
2800 | char __iomem *iop_firm_model = (char __iomem *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ |
2801 | char __iomem *iop_firm_version = (char __iomem *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ | |
cdd3cb15 NC |
2802 | int count; |
2803 | /* disable all outbound interrupt */ | |
2804 | intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */ | |
2805 | writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); | |
2806 | /* wait firmware ready */ | |
2807 | do { | |
2808 | firmware_state = readl(®->outbound_msgaddr1); | |
2809 | } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); | |
2810 | /* post "get config" instruction */ | |
2811 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | |
2812 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
2813 | /* wait message ready */ | |
2814 | for (Index = 0; Index < 2000; Index++) { | |
2815 | if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | |
2816 | writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);/*clear interrupt*/ | |
2817 | break; | |
2818 | } | |
2819 | udelay(10); | |
2820 | } /*max 1 seconds*/ | |
2821 | if (Index >= 2000) { | |
2822 | printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ | |
2823 | miscellaneous data' timeout \n", pACB->host->host_no); | |
2824 | return false; | |
2825 | } | |
2826 | count = 8; | |
2827 | while (count) { | |
2828 | *acb_firm_model = readb(iop_firm_model); | |
2829 | acb_firm_model++; | |
2830 | iop_firm_model++; | |
2831 | count--; | |
2832 | } | |
2833 | count = 16; | |
2834 | while (count) { | |
2835 | *acb_firm_version = readb(iop_firm_version); | |
2836 | acb_firm_version++; | |
2837 | iop_firm_version++; | |
2838 | count--; | |
2839 | } | |
a2c89bbc | 2840 | pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", |
cdd3cb15 | 2841 | pACB->host->host_no, |
a2c89bbc CH |
2842 | pACB->firm_model, |
2843 | pACB->firm_version); | |
cdd3cb15 NC |
2844 | pACB->firm_request_len = readl(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/ |
2845 | pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/ | |
2846 | pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/ | |
2847 | pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/ | |
2848 | pACB->firm_cfg_version = readl(®->msgcode_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ | |
2849 | /*all interrupt service will be enable at arcmsr_iop_init*/ | |
2850 | return true; | |
2851 | } | |
5b37479a CH |
2852 | |
2853 | static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb) | |
2854 | { | |
2855 | char *acb_firm_model = acb->firm_model; | |
2856 | char *acb_firm_version = acb->firm_version; | |
2857 | char *acb_device_map = acb->device_map; | |
2858 | char __iomem *iop_firm_model; | |
2859 | char __iomem *iop_firm_version; | |
2860 | char __iomem *iop_device_map; | |
2861 | u32 count; | |
02040670 | 2862 | struct MessageUnit_D *reg = acb->pmuD; |
5b37479a | 2863 | |
5b37479a CH |
2864 | iop_firm_model = (char __iomem *)(®->msgcode_rwbuffer[15]); |
2865 | iop_firm_version = (char __iomem *)(®->msgcode_rwbuffer[17]); | |
2866 | iop_device_map = (char __iomem *)(®->msgcode_rwbuffer[21]); | |
2867 | if (readl(acb->pmuD->outbound_doorbell) & | |
2868 | ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) { | |
2869 | writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE, | |
2870 | acb->pmuD->outbound_doorbell);/*clear interrupt*/ | |
2871 | } | |
2872 | /* post "get config" instruction */ | |
2873 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, reg->inbound_msgaddr0); | |
2874 | /* wait message ready */ | |
2875 | if (!arcmsr_hbaD_wait_msgint_ready(acb)) { | |
2876 | pr_notice("arcmsr%d: wait get adapter firmware " | |
2877 | "miscellaneous data timeout\n", acb->host->host_no); | |
5b37479a CH |
2878 | return false; |
2879 | } | |
2880 | count = 8; | |
2881 | while (count) { | |
2882 | *acb_firm_model = readb(iop_firm_model); | |
2883 | acb_firm_model++; | |
2884 | iop_firm_model++; | |
2885 | count--; | |
2886 | } | |
2887 | count = 16; | |
2888 | while (count) { | |
2889 | *acb_firm_version = readb(iop_firm_version); | |
2890 | acb_firm_version++; | |
2891 | iop_firm_version++; | |
2892 | count--; | |
2893 | } | |
2894 | count = 16; | |
2895 | while (count) { | |
2896 | *acb_device_map = readb(iop_device_map); | |
2897 | acb_device_map++; | |
2898 | iop_device_map++; | |
2899 | count--; | |
2900 | } | |
251e2d25 | 2901 | acb->signature = readl(®->msgcode_rwbuffer[0]); |
5b37479a | 2902 | /*firm_signature,1,00-03*/ |
251e2d25 | 2903 | acb->firm_request_len = readl(®->msgcode_rwbuffer[1]); |
5b37479a | 2904 | /*firm_request_len,1,04-07*/ |
251e2d25 | 2905 | acb->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); |
5b37479a | 2906 | /*firm_numbers_queue,2,08-11*/ |
251e2d25 | 2907 | acb->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); |
5b37479a | 2908 | /*firm_sdram_size,3,12-15*/ |
251e2d25 | 2909 | acb->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); |
5b37479a CH |
2910 | /*firm_hd_channels,4,16-19*/ |
2911 | acb->firm_cfg_version = readl(®->msgcode_rwbuffer[25]); | |
2912 | pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", | |
2913 | acb->host->host_no, | |
2914 | acb->firm_model, | |
2915 | acb->firm_version); | |
2916 | return true; | |
2917 | } | |
2918 | ||
ae52e7f0 | 2919 | static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) |
1a4f550a | 2920 | { |
3df824af CH |
2921 | bool rtn = false; |
2922 | ||
2923 | switch (acb->adapter_type) { | |
2924 | case ACB_ADAPTER_TYPE_A: | |
626fa32c | 2925 | rtn = arcmsr_hbaA_get_config(acb); |
3df824af CH |
2926 | break; |
2927 | case ACB_ADAPTER_TYPE_B: | |
626fa32c | 2928 | rtn = arcmsr_hbaB_get_config(acb); |
3df824af CH |
2929 | break; |
2930 | case ACB_ADAPTER_TYPE_C: | |
626fa32c | 2931 | rtn = arcmsr_hbaC_get_config(acb); |
3df824af | 2932 | break; |
5b37479a CH |
2933 | case ACB_ADAPTER_TYPE_D: |
2934 | rtn = arcmsr_hbaD_get_config(acb); | |
2935 | break; | |
3df824af CH |
2936 | default: |
2937 | break; | |
2938 | } | |
2939 | if (acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD) | |
2940 | acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD; | |
cdd3cb15 | 2941 | else |
3df824af CH |
2942 | acb->maxOutstanding = acb->firm_numbers_queue - 1; |
2943 | acb->host->can_queue = acb->maxOutstanding; | |
2944 | return rtn; | |
1a4f550a NC |
2945 | } |
2946 | ||
626fa32c | 2947 | static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb, |
1c57e86d EC |
2948 | struct CommandControlBlock *poll_ccb) |
2949 | { | |
80da1adb | 2950 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1c57e86d | 2951 | struct CommandControlBlock *ccb; |
ae52e7f0 | 2952 | struct ARCMSR_CDB *arcmsr_cdb; |
1c57e86d | 2953 | uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; |
ae52e7f0 | 2954 | int rtn; |
cdd3cb15 | 2955 | bool error; |
1a4f550a | 2956 | polling_hba_ccb_retry: |
1c57e86d | 2957 | poll_count++; |
1a4f550a | 2958 | outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; |
1c57e86d EC |
2959 | writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ |
2960 | while (1) { | |
2961 | if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { | |
cdd3cb15 | 2962 | if (poll_ccb_done){ |
ae52e7f0 | 2963 | rtn = SUCCESS; |
1c57e86d | 2964 | break; |
cdd3cb15 NC |
2965 | }else { |
2966 | msleep(25); | |
2967 | if (poll_count > 100){ | |
ae52e7f0 | 2968 | rtn = FAILED; |
1c57e86d | 2969 | break; |
ae52e7f0 | 2970 | } |
1a4f550a | 2971 | goto polling_hba_ccb_retry; |
1c57e86d EC |
2972 | } |
2973 | } | |
ae52e7f0 NC |
2974 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); |
2975 | ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | |
cab5aece | 2976 | poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; |
1a4f550a NC |
2977 | if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { |
2978 | if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { | |
2979 | printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" | |
1c57e86d EC |
2980 | " poll command abort successfully \n" |
2981 | , acb->host->host_no | |
2982 | , ccb->pcmd->device->id | |
9cb78c16 | 2983 | , (u32)ccb->pcmd->device->lun |
1c57e86d EC |
2984 | , ccb); |
2985 | ccb->pcmd->result = DID_ABORT << 16; | |
ae52e7f0 | 2986 | arcmsr_ccb_complete(ccb); |
1c57e86d EC |
2987 | continue; |
2988 | } | |
1a4f550a NC |
2989 | printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" |
2990 | " command done ccb = '0x%p'" | |
a1f6e021 | 2991 | "ccboutstandingcount = %d \n" |
1c57e86d EC |
2992 | , acb->host->host_no |
2993 | , ccb | |
2994 | , atomic_read(&acb->ccboutstandingcount)); | |
2995 | continue; | |
cdd3cb15 NC |
2996 | } |
2997 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
2998 | arcmsr_report_ccb_state(acb, ccb, error); | |
1a4f550a | 2999 | } |
ae52e7f0 NC |
3000 | return rtn; |
3001 | } | |
1a4f550a | 3002 | |
626fa32c | 3003 | static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb, |
1a4f550a NC |
3004 | struct CommandControlBlock *poll_ccb) |
3005 | { | |
cdd3cb15 | 3006 | struct MessageUnit_B *reg = acb->pmuB; |
ae52e7f0 | 3007 | struct ARCMSR_CDB *arcmsr_cdb; |
cdd3cb15 NC |
3008 | struct CommandControlBlock *ccb; |
3009 | uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; | |
ae52e7f0 | 3010 | int index, rtn; |
cdd3cb15 | 3011 | bool error; |
1a4f550a | 3012 | polling_hbb_ccb_retry: |
97b99127 | 3013 | |
cdd3cb15 NC |
3014 | poll_count++; |
3015 | /* clear doorbell interrupt */ | |
ae52e7f0 | 3016 | writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); |
cdd3cb15 NC |
3017 | while(1){ |
3018 | index = reg->doneq_index; | |
c10b1d54 CH |
3019 | flag_ccb = reg->done_qbuffer[index]; |
3020 | if (flag_ccb == 0) { | |
cdd3cb15 | 3021 | if (poll_ccb_done){ |
ae52e7f0 | 3022 | rtn = SUCCESS; |
cdd3cb15 NC |
3023 | break; |
3024 | }else { | |
3025 | msleep(25); | |
3026 | if (poll_count > 100){ | |
ae52e7f0 | 3027 | rtn = FAILED; |
cdd3cb15 | 3028 | break; |
1c57e86d | 3029 | } |
cdd3cb15 | 3030 | goto polling_hbb_ccb_retry; |
1a4f550a | 3031 | } |
cdd3cb15 | 3032 | } |
c10b1d54 | 3033 | reg->done_qbuffer[index] = 0; |
cdd3cb15 NC |
3034 | index++; |
3035 | /*if last index number set it to 0 */ | |
3036 | index %= ARCMSR_MAX_HBB_POSTQUEUE; | |
3037 | reg->doneq_index = index; | |
3038 | /* check if command done with no error*/ | |
ae52e7f0 NC |
3039 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); |
3040 | ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | |
cab5aece | 3041 | poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; |
cdd3cb15 NC |
3042 | if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { |
3043 | if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { | |
ae52e7f0 NC |
3044 | printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" |
3045 | " poll command abort successfully \n" | |
cdd3cb15 NC |
3046 | ,acb->host->host_no |
3047 | ,ccb->pcmd->device->id | |
9cb78c16 | 3048 | ,(u32)ccb->pcmd->device->lun |
cdd3cb15 NC |
3049 | ,ccb); |
3050 | ccb->pcmd->result = DID_ABORT << 16; | |
ae52e7f0 | 3051 | arcmsr_ccb_complete(ccb); |
cdd3cb15 NC |
3052 | continue; |
3053 | } | |
3054 | printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" | |
3055 | " command done ccb = '0x%p'" | |
3056 | "ccboutstandingcount = %d \n" | |
3057 | , acb->host->host_no | |
3058 | , ccb | |
3059 | , atomic_read(&acb->ccboutstandingcount)); | |
3060 | continue; | |
3061 | } | |
3062 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | |
3063 | arcmsr_report_ccb_state(acb, ccb, error); | |
3064 | } | |
3065 | return rtn; | |
3066 | } | |
3067 | ||
626fa32c CH |
3068 | static int arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb, |
3069 | struct CommandControlBlock *poll_ccb) | |
cdd3cb15 | 3070 | { |
c10b1d54 | 3071 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
3072 | uint32_t flag_ccb, ccb_cdb_phy; |
3073 | struct ARCMSR_CDB *arcmsr_cdb; | |
3074 | bool error; | |
3075 | struct CommandControlBlock *pCCB; | |
3076 | uint32_t poll_ccb_done = 0, poll_count = 0; | |
3077 | int rtn; | |
3078 | polling_hbc_ccb_retry: | |
3079 | poll_count++; | |
3080 | while (1) { | |
3081 | if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) { | |
3082 | if (poll_ccb_done) { | |
3083 | rtn = SUCCESS; | |
3084 | break; | |
3085 | } else { | |
3086 | msleep(25); | |
3087 | if (poll_count > 100) { | |
3088 | rtn = FAILED; | |
3089 | break; | |
1c57e86d | 3090 | } |
cdd3cb15 NC |
3091 | goto polling_hbc_ccb_retry; |
3092 | } | |
3093 | } | |
3094 | flag_ccb = readl(®->outbound_queueport_low); | |
3095 | ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | |
3096 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ | |
3097 | pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | |
cab5aece | 3098 | poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0; |
cdd3cb15 NC |
3099 | /* check ifcommand done with no error*/ |
3100 | if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { | |
3101 | if (pCCB->startdone == ARCMSR_CCB_ABORTED) { | |
3102 | printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" | |
3103 | " poll command abort successfully \n" | |
1c57e86d | 3104 | , acb->host->host_no |
cdd3cb15 | 3105 | , pCCB->pcmd->device->id |
9cb78c16 | 3106 | , (u32)pCCB->pcmd->device->lun |
cdd3cb15 NC |
3107 | , pCCB); |
3108 | pCCB->pcmd->result = DID_ABORT << 16; | |
3109 | arcmsr_ccb_complete(pCCB); | |
1a4f550a | 3110 | continue; |
cdd3cb15 NC |
3111 | } |
3112 | printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" | |
3113 | " command done ccb = '0x%p'" | |
3114 | "ccboutstandingcount = %d \n" | |
3115 | , acb->host->host_no | |
3116 | , pCCB | |
3117 | , atomic_read(&acb->ccboutstandingcount)); | |
3118 | continue; | |
ae52e7f0 | 3119 | } |
cdd3cb15 NC |
3120 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; |
3121 | arcmsr_report_ccb_state(acb, pCCB, error); | |
3122 | } | |
ae52e7f0 | 3123 | return rtn; |
1a4f550a | 3124 | } |
5b37479a CH |
3125 | |
3126 | static int arcmsr_hbaD_polling_ccbdone(struct AdapterControlBlock *acb, | |
3127 | struct CommandControlBlock *poll_ccb) | |
3128 | { | |
3129 | bool error; | |
3130 | uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy; | |
3b8155d5 | 3131 | int rtn, doneq_index, index_stripped, outbound_write_pointer, toggle; |
5b37479a CH |
3132 | unsigned long flags; |
3133 | struct ARCMSR_CDB *arcmsr_cdb; | |
3134 | struct CommandControlBlock *pCCB; | |
3135 | struct MessageUnit_D *pmu = acb->pmuD; | |
3136 | ||
3137 | polling_hbaD_ccb_retry: | |
3138 | poll_count++; | |
3139 | while (1) { | |
3b8155d5 | 3140 | spin_lock_irqsave(&acb->doneq_lock, flags); |
5b37479a CH |
3141 | outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1; |
3142 | doneq_index = pmu->doneq_index; | |
3143 | if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) { | |
3b8155d5 | 3144 | spin_unlock_irqrestore(&acb->doneq_lock, flags); |
5b37479a CH |
3145 | if (poll_ccb_done) { |
3146 | rtn = SUCCESS; | |
3147 | break; | |
3148 | } else { | |
3149 | msleep(25); | |
3150 | if (poll_count > 40) { | |
3151 | rtn = FAILED; | |
3152 | break; | |
3153 | } | |
3154 | goto polling_hbaD_ccb_retry; | |
3155 | } | |
3156 | } | |
3b8155d5 CH |
3157 | toggle = doneq_index & 0x4000; |
3158 | index_stripped = (doneq_index & 0xFFF) + 1; | |
3159 | index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE; | |
3160 | pmu->doneq_index = index_stripped ? (index_stripped | toggle) : | |
3161 | ((toggle ^ 0x4000) + 1); | |
5b37479a | 3162 | doneq_index = pmu->doneq_index; |
3b8155d5 | 3163 | spin_unlock_irqrestore(&acb->doneq_lock, flags); |
5b37479a CH |
3164 | flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow; |
3165 | ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | |
3166 | arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + | |
3167 | ccb_cdb_phy); | |
3168 | pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, | |
3169 | arcmsr_cdb); | |
3170 | poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0; | |
3171 | if ((pCCB->acb != acb) || | |
3172 | (pCCB->startdone != ARCMSR_CCB_START)) { | |
3173 | if (pCCB->startdone == ARCMSR_CCB_ABORTED) { | |
3174 | pr_notice("arcmsr%d: scsi id = %d " | |
3175 | "lun = %d ccb = '0x%p' poll command " | |
3176 | "abort successfully\n" | |
3177 | , acb->host->host_no | |
3178 | , pCCB->pcmd->device->id | |
3179 | , (u32)pCCB->pcmd->device->lun | |
3180 | , pCCB); | |
3181 | pCCB->pcmd->result = DID_ABORT << 16; | |
3182 | arcmsr_ccb_complete(pCCB); | |
3183 | continue; | |
3184 | } | |
3185 | pr_notice("arcmsr%d: polling an illegal " | |
3186 | "ccb command done ccb = '0x%p' " | |
3187 | "ccboutstandingcount = %d\n" | |
3188 | , acb->host->host_no | |
3189 | , pCCB | |
3190 | , atomic_read(&acb->ccboutstandingcount)); | |
3191 | continue; | |
3192 | } | |
3193 | error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) | |
3194 | ? true : false; | |
3195 | arcmsr_report_ccb_state(acb, pCCB, error); | |
3196 | } | |
3197 | return rtn; | |
3198 | } | |
3199 | ||
ae52e7f0 | 3200 | static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, |
1a4f550a NC |
3201 | struct CommandControlBlock *poll_ccb) |
3202 | { | |
ae52e7f0 | 3203 | int rtn = 0; |
1a4f550a NC |
3204 | switch (acb->adapter_type) { |
3205 | ||
3206 | case ACB_ADAPTER_TYPE_A: { | |
626fa32c | 3207 | rtn = arcmsr_hbaA_polling_ccbdone(acb, poll_ccb); |
1a4f550a NC |
3208 | } |
3209 | break; | |
3210 | ||
3211 | case ACB_ADAPTER_TYPE_B: { | |
626fa32c | 3212 | rtn = arcmsr_hbaB_polling_ccbdone(acb, poll_ccb); |
1c57e86d | 3213 | } |
cdd3cb15 NC |
3214 | break; |
3215 | case ACB_ADAPTER_TYPE_C: { | |
626fa32c | 3216 | rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb); |
cdd3cb15 | 3217 | } |
5b37479a CH |
3218 | break; |
3219 | case ACB_ADAPTER_TYPE_D: | |
3220 | rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb); | |
3221 | break; | |
1c57e86d | 3222 | } |
ae52e7f0 | 3223 | return rtn; |
1c57e86d | 3224 | } |
1a4f550a NC |
3225 | |
3226 | static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) | |
a1f6e021 | 3227 | { |
ae52e7f0 | 3228 | uint32_t cdb_phyaddr, cdb_phyaddr_hi32; |
6e38adfc | 3229 | dma_addr_t dma_coherent_handle; |
e2c70425 | 3230 | |
1a4f550a NC |
3231 | /* |
3232 | ******************************************************************** | |
3233 | ** here we need to tell iop 331 our freeccb.HighPart | |
3234 | ** if freeccb.HighPart is not zero | |
3235 | ******************************************************************** | |
3236 | */ | |
6e38adfc CH |
3237 | switch (acb->adapter_type) { |
3238 | case ACB_ADAPTER_TYPE_B: | |
5b37479a | 3239 | case ACB_ADAPTER_TYPE_D: |
6e38adfc CH |
3240 | dma_coherent_handle = acb->dma_coherent_handle2; |
3241 | break; | |
3242 | default: | |
3243 | dma_coherent_handle = acb->dma_coherent_handle; | |
3244 | break; | |
3245 | } | |
3246 | cdb_phyaddr = lower_32_bits(dma_coherent_handle); | |
3247 | cdb_phyaddr_hi32 = upper_32_bits(dma_coherent_handle); | |
cdd3cb15 | 3248 | acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; |
1a4f550a NC |
3249 | /* |
3250 | *********************************************************************** | |
3251 | ** if adapter type B, set window of "post command Q" | |
3252 | *********************************************************************** | |
3253 | */ | |
3254 | switch (acb->adapter_type) { | |
3255 | ||
3256 | case ACB_ADAPTER_TYPE_A: { | |
ae52e7f0 | 3257 | if (cdb_phyaddr_hi32 != 0) { |
80da1adb | 3258 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
3259 | writel(ARCMSR_SIGNATURE_SET_CONFIG, \ |
3260 | ®->message_rwbuffer[0]); | |
ae52e7f0 | 3261 | writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); |
1a4f550a NC |
3262 | writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ |
3263 | ®->inbound_msgaddr0); | |
626fa32c | 3264 | if (!arcmsr_hbaA_wait_msgint_ready(acb)) { |
1a4f550a NC |
3265 | printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ |
3266 | part physical address timeout\n", | |
3267 | acb->host->host_no); | |
3268 | return 1; | |
a1f6e021 | 3269 | } |
1a4f550a NC |
3270 | } |
3271 | } | |
3272 | break; | |
a1f6e021 | 3273 | |
1a4f550a | 3274 | case ACB_ADAPTER_TYPE_B: { |
80da1adb | 3275 | uint32_t __iomem *rwbuffer; |
a1f6e021 | 3276 | |
80da1adb | 3277 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a NC |
3278 | reg->postq_index = 0; |
3279 | reg->doneq_index = 0; | |
ae52e7f0 | 3280 | writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); |
626fa32c | 3281 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
47268a4f | 3282 | printk(KERN_NOTICE "arcmsr%d: cannot set driver mode\n", \ |
1a4f550a NC |
3283 | acb->host->host_no); |
3284 | return 1; | |
3285 | } | |
ae52e7f0 | 3286 | rwbuffer = reg->message_rwbuffer; |
1a4f550a NC |
3287 | /* driver "set config" signature */ |
3288 | writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); | |
3289 | /* normal should be zero */ | |
ae52e7f0 | 3290 | writel(cdb_phyaddr_hi32, rwbuffer++); |
1a4f550a | 3291 | /* postQ size (256 + 8)*4 */ |
6e38adfc | 3292 | writel(cdb_phyaddr, rwbuffer++); |
1a4f550a | 3293 | /* doneQ size (256 + 8)*4 */ |
6e38adfc | 3294 | writel(cdb_phyaddr + 1056, rwbuffer++); |
1a4f550a NC |
3295 | /* ccb maxQ size must be --> [(256 + 8)*4]*/ |
3296 | writel(1056, rwbuffer); | |
3297 | ||
ae52e7f0 | 3298 | writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); |
626fa32c | 3299 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
1a4f550a NC |
3300 | printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ |
3301 | timeout \n",acb->host->host_no); | |
3302 | return 1; | |
3303 | } | |
a5849726 | 3304 | writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); |
626fa32c | 3305 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
a5849726 CH |
3306 | pr_err("arcmsr%d: can't set driver mode.\n", |
3307 | acb->host->host_no); | |
3308 | return 1; | |
3309 | } | |
1a4f550a NC |
3310 | } |
3311 | break; | |
cdd3cb15 NC |
3312 | case ACB_ADAPTER_TYPE_C: { |
3313 | if (cdb_phyaddr_hi32 != 0) { | |
c10b1d54 | 3314 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 | 3315 | |
8b7eb86f TH |
3316 | printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", |
3317 | acb->adapter_index, cdb_phyaddr_hi32); | |
cdd3cb15 NC |
3318 | writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); |
3319 | writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); | |
3320 | writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); | |
3321 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
626fa32c | 3322 | if (!arcmsr_hbaC_wait_msgint_ready(acb)) { |
cdd3cb15 NC |
3323 | printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ |
3324 | timeout \n", acb->host->host_no); | |
3325 | return 1; | |
3326 | } | |
3327 | } | |
3328 | } | |
5b37479a CH |
3329 | break; |
3330 | case ACB_ADAPTER_TYPE_D: { | |
3331 | uint32_t __iomem *rwbuffer; | |
3332 | struct MessageUnit_D *reg = acb->pmuD; | |
3333 | reg->postq_index = 0; | |
3334 | reg->doneq_index = 0; | |
3335 | rwbuffer = reg->msgcode_rwbuffer; | |
3336 | writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); | |
3337 | writel(cdb_phyaddr_hi32, rwbuffer++); | |
3338 | writel(cdb_phyaddr, rwbuffer++); | |
3339 | writel(cdb_phyaddr + (ARCMSR_MAX_ARC1214_POSTQUEUE * | |
3340 | sizeof(struct InBound_SRB)), rwbuffer++); | |
3341 | writel(0x100, rwbuffer); | |
3342 | writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, reg->inbound_msgaddr0); | |
3343 | if (!arcmsr_hbaD_wait_msgint_ready(acb)) { | |
3344 | pr_notice("arcmsr%d: 'set command Q window' timeout\n", | |
3345 | acb->host->host_no); | |
3346 | return 1; | |
3347 | } | |
3348 | } | |
3349 | break; | |
1a4f550a NC |
3350 | } |
3351 | return 0; | |
3352 | } | |
a1f6e021 | 3353 | |
1a4f550a NC |
3354 | static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) |
3355 | { | |
3356 | uint32_t firmware_state = 0; | |
1a4f550a NC |
3357 | switch (acb->adapter_type) { |
3358 | ||
3359 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 3360 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
3361 | do { |
3362 | firmware_state = readl(®->outbound_msgaddr1); | |
3363 | } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); | |
3364 | } | |
3365 | break; | |
3366 | ||
3367 | case ACB_ADAPTER_TYPE_B: { | |
80da1adb | 3368 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 3369 | do { |
ae52e7f0 | 3370 | firmware_state = readl(reg->iop2drv_doorbell); |
1a4f550a | 3371 | } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); |
ae52e7f0 | 3372 | writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); |
1a4f550a NC |
3373 | } |
3374 | break; | |
cdd3cb15 | 3375 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 3376 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
cdd3cb15 NC |
3377 | do { |
3378 | firmware_state = readl(®->outbound_msgaddr1); | |
3379 | } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); | |
3380 | } | |
5b37479a CH |
3381 | break; |
3382 | case ACB_ADAPTER_TYPE_D: { | |
3383 | struct MessageUnit_D *reg = acb->pmuD; | |
3384 | do { | |
3385 | firmware_state = readl(reg->outbound_msgaddr1); | |
3386 | } while ((firmware_state & | |
3387 | ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0); | |
3388 | } | |
3389 | break; | |
a1f6e021 | 3390 | } |
1a4f550a NC |
3391 | } |
3392 | ||
626fa32c | 3393 | static void arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb) |
36b83ded NC |
3394 | { |
3395 | struct MessageUnit_A __iomem *reg = acb->pmuA; | |
cdd3cb15 | 3396 | if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ |
97b99127 | 3397 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
ae52e7f0 | 3398 | return; |
36b83ded | 3399 | } else { |
ae52e7f0 | 3400 | acb->fw_flag = FW_NORMAL; |
cdd3cb15 | 3401 | if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){ |
36b83ded NC |
3402 | atomic_set(&acb->rq_map_token, 16); |
3403 | } | |
ae52e7f0 | 3404 | atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); |
97b99127 N |
3405 | if (atomic_dec_and_test(&acb->rq_map_token)) { |
3406 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
ae52e7f0 | 3407 | return; |
97b99127 | 3408 | } |
36b83ded | 3409 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); |
cdd3cb15 | 3410 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
36b83ded | 3411 | } |
36b83ded NC |
3412 | return; |
3413 | } | |
3414 | ||
626fa32c | 3415 | static void arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb) |
36b83ded | 3416 | { |
c10b1d54 | 3417 | struct MessageUnit_B *reg = acb->pmuB; |
cdd3cb15 | 3418 | if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ |
97b99127 | 3419 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
cdd3cb15 NC |
3420 | return; |
3421 | } else { | |
3422 | acb->fw_flag = FW_NORMAL; | |
3423 | if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { | |
97b99127 | 3424 | atomic_set(&acb->rq_map_token, 16); |
cdd3cb15 NC |
3425 | } |
3426 | atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); | |
97b99127 N |
3427 | if (atomic_dec_and_test(&acb->rq_map_token)) { |
3428 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
cdd3cb15 | 3429 | return; |
97b99127 | 3430 | } |
cdd3cb15 NC |
3431 | writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); |
3432 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
3433 | } | |
3434 | return; | |
3435 | } | |
36b83ded | 3436 | |
626fa32c | 3437 | static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb) |
cdd3cb15 NC |
3438 | { |
3439 | struct MessageUnit_C __iomem *reg = acb->pmuC; | |
ae52e7f0 | 3440 | if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { |
97b99127 | 3441 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
ae52e7f0 | 3442 | return; |
36b83ded | 3443 | } else { |
ae52e7f0 NC |
3444 | acb->fw_flag = FW_NORMAL; |
3445 | if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { | |
36b83ded NC |
3446 | atomic_set(&acb->rq_map_token, 16); |
3447 | } | |
ae52e7f0 | 3448 | atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); |
97b99127 N |
3449 | if (atomic_dec_and_test(&acb->rq_map_token)) { |
3450 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
ae52e7f0 | 3451 | return; |
97b99127 | 3452 | } |
cdd3cb15 NC |
3453 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); |
3454 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | |
3455 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
36b83ded | 3456 | } |
36b83ded NC |
3457 | return; |
3458 | } | |
3459 | ||
5b37479a CH |
3460 | static void arcmsr_hbaD_request_device_map(struct AdapterControlBlock *acb) |
3461 | { | |
3462 | struct MessageUnit_D *reg = acb->pmuD; | |
3463 | ||
3464 | if (unlikely(atomic_read(&acb->rq_map_token) == 0) || | |
3465 | ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || | |
3466 | ((acb->acb_flags & ACB_F_ABORT) != 0)) { | |
3467 | mod_timer(&acb->eternal_timer, | |
3468 | jiffies + msecs_to_jiffies(6 * HZ)); | |
3469 | } else { | |
3470 | acb->fw_flag = FW_NORMAL; | |
3471 | if (atomic_read(&acb->ante_token_value) == | |
3472 | atomic_read(&acb->rq_map_token)) { | |
3473 | atomic_set(&acb->rq_map_token, 16); | |
3474 | } | |
3475 | atomic_set(&acb->ante_token_value, | |
3476 | atomic_read(&acb->rq_map_token)); | |
3477 | if (atomic_dec_and_test(&acb->rq_map_token)) { | |
3478 | mod_timer(&acb->eternal_timer, jiffies + | |
3479 | msecs_to_jiffies(6 * HZ)); | |
3480 | return; | |
3481 | } | |
3482 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, | |
3483 | reg->inbound_msgaddr0); | |
3484 | mod_timer(&acb->eternal_timer, jiffies + | |
3485 | msecs_to_jiffies(6 * HZ)); | |
3486 | } | |
3487 | } | |
3488 | ||
36b83ded NC |
3489 | static void arcmsr_request_device_map(unsigned long pacb) |
3490 | { | |
3491 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb; | |
36b83ded NC |
3492 | switch (acb->adapter_type) { |
3493 | case ACB_ADAPTER_TYPE_A: { | |
626fa32c | 3494 | arcmsr_hbaA_request_device_map(acb); |
36b83ded NC |
3495 | } |
3496 | break; | |
3497 | case ACB_ADAPTER_TYPE_B: { | |
626fa32c | 3498 | arcmsr_hbaB_request_device_map(acb); |
36b83ded NC |
3499 | } |
3500 | break; | |
cdd3cb15 | 3501 | case ACB_ADAPTER_TYPE_C: { |
626fa32c | 3502 | arcmsr_hbaC_request_device_map(acb); |
cdd3cb15 | 3503 | } |
5b37479a CH |
3504 | break; |
3505 | case ACB_ADAPTER_TYPE_D: | |
3506 | arcmsr_hbaD_request_device_map(acb); | |
3507 | break; | |
36b83ded NC |
3508 | } |
3509 | } | |
3510 | ||
626fa32c | 3511 | static void arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb) |
1a4f550a | 3512 | { |
80da1adb | 3513 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
3514 | acb->acb_flags |= ACB_F_MSG_START_BGRB; |
3515 | writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); | |
626fa32c | 3516 | if (!arcmsr_hbaA_wait_msgint_ready(acb)) { |
1a4f550a NC |
3517 | printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ |
3518 | rebulid' timeout \n", acb->host->host_no); | |
a1f6e021 | 3519 | } |
a1f6e021 | 3520 | } |
3521 | ||
626fa32c | 3522 | static void arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb) |
1a4f550a | 3523 | { |
80da1adb | 3524 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 3525 | acb->acb_flags |= ACB_F_MSG_START_BGRB; |
ae52e7f0 | 3526 | writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); |
626fa32c | 3527 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
1a4f550a NC |
3528 | printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ |
3529 | rebulid' timeout \n",acb->host->host_no); | |
3530 | } | |
3531 | } | |
1c57e86d | 3532 | |
626fa32c | 3533 | static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB) |
cdd3cb15 | 3534 | { |
c10b1d54 | 3535 | struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; |
cdd3cb15 NC |
3536 | pACB->acb_flags |= ACB_F_MSG_START_BGRB; |
3537 | writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0); | |
3538 | writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); | |
626fa32c | 3539 | if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { |
cdd3cb15 NC |
3540 | printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ |
3541 | rebulid' timeout \n", pACB->host->host_no); | |
3542 | } | |
3543 | return; | |
3544 | } | |
5b37479a CH |
3545 | |
3546 | static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB) | |
3547 | { | |
3548 | struct MessageUnit_D *pmu = pACB->pmuD; | |
3549 | ||
3550 | pACB->acb_flags |= ACB_F_MSG_START_BGRB; | |
3551 | writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0); | |
3552 | if (!arcmsr_hbaD_wait_msgint_ready(pACB)) { | |
3553 | pr_notice("arcmsr%d: wait 'start adapter " | |
3554 | "background rebulid' timeout\n", pACB->host->host_no); | |
3555 | } | |
3556 | } | |
3557 | ||
1a4f550a | 3558 | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) |
1c57e86d | 3559 | { |
1a4f550a NC |
3560 | switch (acb->adapter_type) { |
3561 | case ACB_ADAPTER_TYPE_A: | |
626fa32c | 3562 | arcmsr_hbaA_start_bgrb(acb); |
1a4f550a NC |
3563 | break; |
3564 | case ACB_ADAPTER_TYPE_B: | |
626fa32c | 3565 | arcmsr_hbaB_start_bgrb(acb); |
1a4f550a | 3566 | break; |
cdd3cb15 | 3567 | case ACB_ADAPTER_TYPE_C: |
626fa32c | 3568 | arcmsr_hbaC_start_bgrb(acb); |
5b37479a CH |
3569 | break; |
3570 | case ACB_ADAPTER_TYPE_D: | |
3571 | arcmsr_hbaD_start_bgrb(acb); | |
3572 | break; | |
1a4f550a NC |
3573 | } |
3574 | } | |
1c57e86d | 3575 | |
1a4f550a NC |
3576 | static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) |
3577 | { | |
3578 | switch (acb->adapter_type) { | |
3579 | case ACB_ADAPTER_TYPE_A: { | |
80da1adb | 3580 | struct MessageUnit_A __iomem *reg = acb->pmuA; |
1a4f550a NC |
3581 | uint32_t outbound_doorbell; |
3582 | /* empty doorbell Qbuffer if door bell ringed */ | |
3583 | outbound_doorbell = readl(®->outbound_doorbell); | |
3584 | /*clear doorbell interrupt */ | |
3585 | writel(outbound_doorbell, ®->outbound_doorbell); | |
3586 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | |
3587 | } | |
3588 | break; | |
1c57e86d | 3589 | |
1a4f550a | 3590 | case ACB_ADAPTER_TYPE_B: { |
80da1adb | 3591 | struct MessageUnit_B *reg = acb->pmuB; |
1a4f550a | 3592 | /*clear interrupt and message state*/ |
ae52e7f0 NC |
3593 | writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); |
3594 | writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); | |
1a4f550a NC |
3595 | /* let IOP know data has been read */ |
3596 | } | |
3597 | break; | |
cdd3cb15 | 3598 | case ACB_ADAPTER_TYPE_C: { |
c10b1d54 | 3599 | struct MessageUnit_C __iomem *reg = acb->pmuC; |
5eb6bfa0 | 3600 | uint32_t outbound_doorbell, i; |
cdd3cb15 NC |
3601 | /* empty doorbell Qbuffer if door bell ringed */ |
3602 | outbound_doorbell = readl(®->outbound_doorbell); | |
3603 | writel(outbound_doorbell, ®->outbound_doorbell_clear); | |
3604 | writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); | |
5eb6bfa0 CH |
3605 | for (i = 0; i < 200; i++) { |
3606 | msleep(20); | |
3607 | outbound_doorbell = readl(®->outbound_doorbell); | |
3608 | if (outbound_doorbell & | |
3609 | ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { | |
3610 | writel(outbound_doorbell, | |
3611 | ®->outbound_doorbell_clear); | |
3612 | writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, | |
3613 | ®->inbound_doorbell); | |
3614 | } else | |
3615 | break; | |
3616 | } | |
cdd3cb15 | 3617 | } |
5b37479a CH |
3618 | break; |
3619 | case ACB_ADAPTER_TYPE_D: { | |
3620 | struct MessageUnit_D *reg = acb->pmuD; | |
3621 | uint32_t outbound_doorbell, i; | |
3622 | /* empty doorbell Qbuffer if door bell ringed */ | |
3623 | outbound_doorbell = readl(reg->outbound_doorbell); | |
3624 | writel(outbound_doorbell, reg->outbound_doorbell); | |
3625 | writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ, | |
3626 | reg->inbound_doorbell); | |
3627 | for (i = 0; i < 200; i++) { | |
3628 | msleep(20); | |
3629 | outbound_doorbell = readl(reg->outbound_doorbell); | |
3630 | if (outbound_doorbell & | |
3631 | ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK) { | |
3632 | writel(outbound_doorbell, | |
3633 | reg->outbound_doorbell); | |
3634 | writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ, | |
3635 | reg->inbound_doorbell); | |
3636 | } else | |
3637 | break; | |
3638 | } | |
3639 | } | |
3640 | break; | |
1c57e86d | 3641 | } |
1a4f550a | 3642 | } |
1c57e86d | 3643 | |
76d78300 NC |
3644 | static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) |
3645 | { | |
3646 | switch (acb->adapter_type) { | |
3647 | case ACB_ADAPTER_TYPE_A: | |
3648 | return; | |
3649 | case ACB_ADAPTER_TYPE_B: | |
3650 | { | |
3651 | struct MessageUnit_B *reg = acb->pmuB; | |
ae52e7f0 | 3652 | writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); |
626fa32c | 3653 | if (!arcmsr_hbaB_wait_msgint_ready(acb)) { |
76d78300 NC |
3654 | printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); |
3655 | return; | |
3656 | } | |
3657 | } | |
3658 | break; | |
cdd3cb15 NC |
3659 | case ACB_ADAPTER_TYPE_C: |
3660 | return; | |
76d78300 NC |
3661 | } |
3662 | return; | |
3663 | } | |
3664 | ||
36b83ded NC |
3665 | static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) |
3666 | { | |
3667 | uint8_t value[64]; | |
cdd3cb15 NC |
3668 | int i, count = 0; |
3669 | struct MessageUnit_A __iomem *pmuA = acb->pmuA; | |
3670 | struct MessageUnit_C __iomem *pmuC = acb->pmuC; | |
5b37479a | 3671 | struct MessageUnit_D *pmuD = acb->pmuD; |
6ad819b0 | 3672 | |
36b83ded | 3673 | /* backup pci config data */ |
cdd3cb15 | 3674 | printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); |
36b83ded NC |
3675 | for (i = 0; i < 64; i++) { |
3676 | pci_read_config_byte(acb->pdev, i, &value[i]); | |
3677 | } | |
3678 | /* hardware reset signal */ | |
ae52e7f0 | 3679 | if ((acb->dev_id == 0x1680)) { |
cdd3cb15 NC |
3680 | writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]); |
3681 | } else if ((acb->dev_id == 0x1880)) { | |
3682 | do { | |
3683 | count++; | |
3684 | writel(0xF, &pmuC->write_sequence); | |
3685 | writel(0x4, &pmuC->write_sequence); | |
3686 | writel(0xB, &pmuC->write_sequence); | |
3687 | writel(0x2, &pmuC->write_sequence); | |
3688 | writel(0x7, &pmuC->write_sequence); | |
3689 | writel(0xD, &pmuC->write_sequence); | |
6ad819b0 | 3690 | } while (((readl(&pmuC->host_diagnostic) & ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5)); |
cdd3cb15 | 3691 | writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic); |
5b37479a CH |
3692 | } else if ((acb->dev_id == 0x1214)) { |
3693 | writel(0x20, pmuD->reset_request); | |
ae52e7f0 | 3694 | } else { |
cdd3cb15 | 3695 | pci_write_config_byte(acb->pdev, 0x84, 0x20); |
ae52e7f0 | 3696 | } |
cdd3cb15 | 3697 | msleep(2000); |
36b83ded NC |
3698 | /* write back pci config data */ |
3699 | for (i = 0; i < 64; i++) { | |
3700 | pci_write_config_byte(acb->pdev, i, value[i]); | |
3701 | } | |
3702 | msleep(1000); | |
3703 | return; | |
3704 | } | |
1a4f550a NC |
3705 | static void arcmsr_iop_init(struct AdapterControlBlock *acb) |
3706 | { | |
3707 | uint32_t intmask_org; | |
cdd3cb15 NC |
3708 | /* disable all outbound interrupt */ |
3709 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
76d78300 NC |
3710 | arcmsr_wait_firmware_ready(acb); |
3711 | arcmsr_iop_confirm(acb); | |
1a4f550a NC |
3712 | /*start background rebuild*/ |
3713 | arcmsr_start_adapter_bgrb(acb); | |
3714 | /* empty doorbell Qbuffer if door bell ringed */ | |
3715 | arcmsr_clear_doorbell_queue_buffer(acb); | |
76d78300 | 3716 | arcmsr_enable_eoi_mode(acb); |
1a4f550a NC |
3717 | /* enable outbound Post Queue,outbound doorbell Interrupt */ |
3718 | arcmsr_enable_outbound_ints(acb, intmask_org); | |
1c57e86d EC |
3719 | acb->acb_flags |= ACB_F_IOP_INITED; |
3720 | } | |
3721 | ||
36b83ded | 3722 | static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) |
1c57e86d | 3723 | { |
1c57e86d EC |
3724 | struct CommandControlBlock *ccb; |
3725 | uint32_t intmask_org; | |
36b83ded | 3726 | uint8_t rtnval = 0x00; |
1c57e86d | 3727 | int i = 0; |
97b99127 N |
3728 | unsigned long flags; |
3729 | ||
1c57e86d | 3730 | if (atomic_read(&acb->ccboutstandingcount) != 0) { |
36b83ded NC |
3731 | /* disable all outbound interrupt */ |
3732 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
1c57e86d | 3733 | /* talk to iop 331 outstanding command aborted */ |
36b83ded | 3734 | rtnval = arcmsr_abort_allcmd(acb); |
1c57e86d | 3735 | /* clear all outbound posted Q */ |
1a4f550a | 3736 | arcmsr_done4abort_postqueue(acb); |
1c57e86d EC |
3737 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { |
3738 | ccb = acb->pccb_pool[i]; | |
a1f6e021 | 3739 | if (ccb->startdone == ARCMSR_CCB_START) { |
97b99127 N |
3740 | scsi_dma_unmap(ccb->pcmd); |
3741 | ccb->startdone = ARCMSR_CCB_DONE; | |
3742 | ccb->ccb_flags = 0; | |
3743 | spin_lock_irqsave(&acb->ccblist_lock, flags); | |
3744 | list_add_tail(&ccb->list, &acb->ccb_free_list); | |
3745 | spin_unlock_irqrestore(&acb->ccblist_lock, flags); | |
1c57e86d EC |
3746 | } |
3747 | } | |
36b83ded | 3748 | atomic_set(&acb->ccboutstandingcount, 0); |
1c57e86d EC |
3749 | /* enable all outbound interrupt */ |
3750 | arcmsr_enable_outbound_ints(acb, intmask_org); | |
36b83ded | 3751 | return rtnval; |
1c57e86d | 3752 | } |
36b83ded | 3753 | return rtnval; |
1c57e86d EC |
3754 | } |
3755 | ||
3756 | static int arcmsr_bus_reset(struct scsi_cmnd *cmd) | |
3757 | { | |
97b99127 | 3758 | struct AdapterControlBlock *acb; |
ae52e7f0 NC |
3759 | uint32_t intmask_org, outbound_doorbell; |
3760 | int retry_count = 0; | |
3761 | int rtn = FAILED; | |
ae52e7f0 | 3762 | acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; |
cdd3cb15 | 3763 | printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts); |
36b83ded | 3764 | acb->num_resets++; |
36b83ded | 3765 | |
cdd3cb15 NC |
3766 | switch(acb->adapter_type){ |
3767 | case ACB_ADAPTER_TYPE_A:{ | |
3768 | if (acb->acb_flags & ACB_F_BUS_RESET){ | |
ae52e7f0 | 3769 | long timeout; |
cdd3cb15 NC |
3770 | printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); |
3771 | timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); | |
ae52e7f0 NC |
3772 | if (timeout) { |
3773 | return SUCCESS; | |
3774 | } | |
3775 | } | |
3776 | acb->acb_flags |= ACB_F_BUS_RESET; | |
cdd3cb15 | 3777 | if (!arcmsr_iop_reset(acb)) { |
ae52e7f0 NC |
3778 | struct MessageUnit_A __iomem *reg; |
3779 | reg = acb->pmuA; | |
cdd3cb15 NC |
3780 | arcmsr_hardware_reset(acb); |
3781 | acb->acb_flags &= ~ACB_F_IOP_INITED; | |
36b83ded | 3782 | sleep_again: |
8b7eb86f | 3783 | ssleep(ARCMSR_SLEEPTIME); |
ae52e7f0 | 3784 | if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { |
8b7eb86f TH |
3785 | printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); |
3786 | if (retry_count > ARCMSR_RETRYCOUNT) { | |
ae52e7f0 | 3787 | acb->fw_flag = FW_DEADLOCK; |
8b7eb86f | 3788 | printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); |
ae52e7f0 | 3789 | return FAILED; |
cdd3cb15 NC |
3790 | } |
3791 | retry_count++; | |
3792 | goto sleep_again; | |
3793 | } | |
3794 | acb->acb_flags |= ACB_F_IOP_INITED; | |
3795 | /* disable all outbound interrupt */ | |
3796 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
ae52e7f0 | 3797 | arcmsr_get_firmware_spec(acb); |
cdd3cb15 NC |
3798 | arcmsr_start_adapter_bgrb(acb); |
3799 | /* clear Qbuffer if door bell ringed */ | |
3800 | outbound_doorbell = readl(®->outbound_doorbell); | |
3801 | writel(outbound_doorbell, ®->outbound_doorbell); /*clear interrupt */ | |
3802 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | |
3803 | /* enable outbound Post Queue,outbound doorbell Interrupt */ | |
3804 | arcmsr_enable_outbound_ints(acb, intmask_org); | |
3805 | atomic_set(&acb->rq_map_token, 16); | |
ae52e7f0 NC |
3806 | atomic_set(&acb->ante_token_value, 16); |
3807 | acb->fw_flag = FW_NORMAL; | |
97b99127 | 3808 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
ae52e7f0 NC |
3809 | acb->acb_flags &= ~ACB_F_BUS_RESET; |
3810 | rtn = SUCCESS; | |
cdd3cb15 | 3811 | printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); |
ae52e7f0 NC |
3812 | } else { |
3813 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
97b99127 N |
3814 | atomic_set(&acb->rq_map_token, 16); |
3815 | atomic_set(&acb->ante_token_value, 16); | |
3816 | acb->fw_flag = FW_NORMAL; | |
3817 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); | |
ae52e7f0 | 3818 | rtn = SUCCESS; |
cdd3cb15 | 3819 | } |
ae52e7f0 | 3820 | break; |
36b83ded | 3821 | } |
ae52e7f0 NC |
3822 | case ACB_ADAPTER_TYPE_B:{ |
3823 | acb->acb_flags |= ACB_F_BUS_RESET; | |
cdd3cb15 | 3824 | if (!arcmsr_iop_reset(acb)) { |
ae52e7f0 NC |
3825 | acb->acb_flags &= ~ACB_F_BUS_RESET; |
3826 | rtn = FAILED; | |
cdd3cb15 NC |
3827 | } else { |
3828 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
97b99127 N |
3829 | atomic_set(&acb->rq_map_token, 16); |
3830 | atomic_set(&acb->ante_token_value, 16); | |
3831 | acb->fw_flag = FW_NORMAL; | |
3832 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | |
ae52e7f0 | 3833 | rtn = SUCCESS; |
cdd3cb15 NC |
3834 | } |
3835 | break; | |
3836 | } | |
3837 | case ACB_ADAPTER_TYPE_C:{ | |
3838 | if (acb->acb_flags & ACB_F_BUS_RESET) { | |
3839 | long timeout; | |
3840 | printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); | |
3841 | timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); | |
3842 | if (timeout) { | |
3843 | return SUCCESS; | |
3844 | } | |
3845 | } | |
3846 | acb->acb_flags |= ACB_F_BUS_RESET; | |
3847 | if (!arcmsr_iop_reset(acb)) { | |
3848 | struct MessageUnit_C __iomem *reg; | |
3849 | reg = acb->pmuC; | |
3850 | arcmsr_hardware_reset(acb); | |
3851 | acb->acb_flags &= ~ACB_F_IOP_INITED; | |
3852 | sleep: | |
8b7eb86f | 3853 | ssleep(ARCMSR_SLEEPTIME); |
cdd3cb15 | 3854 | if ((readl(®->host_diagnostic) & 0x04) != 0) { |
8b7eb86f TH |
3855 | printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); |
3856 | if (retry_count > ARCMSR_RETRYCOUNT) { | |
cdd3cb15 | 3857 | acb->fw_flag = FW_DEADLOCK; |
8b7eb86f | 3858 | printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); |
cdd3cb15 NC |
3859 | return FAILED; |
3860 | } | |
3861 | retry_count++; | |
3862 | goto sleep; | |
3863 | } | |
3864 | acb->acb_flags |= ACB_F_IOP_INITED; | |
3865 | /* disable all outbound interrupt */ | |
3866 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
3867 | arcmsr_get_firmware_spec(acb); | |
3868 | arcmsr_start_adapter_bgrb(acb); | |
3869 | /* clear Qbuffer if door bell ringed */ | |
5eb6bfa0 | 3870 | arcmsr_clear_doorbell_queue_buffer(acb); |
cdd3cb15 NC |
3871 | /* enable outbound Post Queue,outbound doorbell Interrupt */ |
3872 | arcmsr_enable_outbound_ints(acb, intmask_org); | |
3873 | atomic_set(&acb->rq_map_token, 16); | |
3874 | atomic_set(&acb->ante_token_value, 16); | |
3875 | acb->fw_flag = FW_NORMAL; | |
97b99127 | 3876 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); |
cdd3cb15 NC |
3877 | acb->acb_flags &= ~ACB_F_BUS_RESET; |
3878 | rtn = SUCCESS; | |
3879 | printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); | |
3880 | } else { | |
3881 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
97b99127 N |
3882 | atomic_set(&acb->rq_map_token, 16); |
3883 | atomic_set(&acb->ante_token_value, 16); | |
3884 | acb->fw_flag = FW_NORMAL; | |
3885 | mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); | |
cdd3cb15 NC |
3886 | rtn = SUCCESS; |
3887 | } | |
3888 | break; | |
ae52e7f0 | 3889 | } |
5b37479a CH |
3890 | case ACB_ADAPTER_TYPE_D: { |
3891 | if (acb->acb_flags & ACB_F_BUS_RESET) { | |
3892 | long timeout; | |
3893 | pr_notice("arcmsr: there is an bus reset" | |
3894 | " eh proceeding.......\n"); | |
3895 | timeout = wait_event_timeout(wait_q, (acb->acb_flags | |
3896 | & ACB_F_BUS_RESET) == 0, 220 * HZ); | |
3897 | if (timeout) | |
3898 | return SUCCESS; | |
3899 | } | |
3900 | acb->acb_flags |= ACB_F_BUS_RESET; | |
3901 | if (!arcmsr_iop_reset(acb)) { | |
3902 | struct MessageUnit_D *reg; | |
3903 | reg = acb->pmuD; | |
3904 | arcmsr_hardware_reset(acb); | |
3905 | acb->acb_flags &= ~ACB_F_IOP_INITED; | |
3906 | nap: | |
3907 | ssleep(ARCMSR_SLEEPTIME); | |
3908 | if ((readl(reg->sample_at_reset) & 0x80) != 0) { | |
3909 | pr_err("arcmsr%d: waiting for " | |
3910 | "hw bus reset return, retry=%d\n", | |
3911 | acb->host->host_no, retry_count); | |
3912 | if (retry_count > ARCMSR_RETRYCOUNT) { | |
3913 | acb->fw_flag = FW_DEADLOCK; | |
3914 | pr_err("arcmsr%d: waiting for hw bus" | |
3915 | " reset return, " | |
3916 | "RETRY TERMINATED!!\n", | |
3917 | acb->host->host_no); | |
3918 | return FAILED; | |
3919 | } | |
3920 | retry_count++; | |
3921 | goto nap; | |
3922 | } | |
3923 | acb->acb_flags |= ACB_F_IOP_INITED; | |
3924 | /* disable all outbound interrupt */ | |
3925 | intmask_org = arcmsr_disable_outbound_ints(acb); | |
3926 | arcmsr_get_firmware_spec(acb); | |
3927 | arcmsr_start_adapter_bgrb(acb); | |
3928 | arcmsr_clear_doorbell_queue_buffer(acb); | |
3929 | arcmsr_enable_outbound_ints(acb, intmask_org); | |
3930 | atomic_set(&acb->rq_map_token, 16); | |
3931 | atomic_set(&acb->ante_token_value, 16); | |
3932 | acb->fw_flag = FW_NORMAL; | |
3933 | mod_timer(&acb->eternal_timer, | |
3934 | jiffies + msecs_to_jiffies(6 * HZ)); | |
3935 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
3936 | rtn = SUCCESS; | |
3937 | pr_err("arcmsr: scsi bus reset " | |
3938 | "eh returns with success\n"); | |
3939 | } else { | |
3940 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
3941 | atomic_set(&acb->rq_map_token, 16); | |
3942 | atomic_set(&acb->ante_token_value, 16); | |
3943 | acb->fw_flag = FW_NORMAL; | |
3944 | mod_timer(&acb->eternal_timer, | |
3945 | jiffies + msecs_to_jiffies(6 * HZ)); | |
3946 | rtn = SUCCESS; | |
3947 | } | |
3948 | break; | |
3949 | } | |
ae52e7f0 NC |
3950 | } |
3951 | return rtn; | |
1c57e86d EC |
3952 | } |
3953 | ||
ae52e7f0 | 3954 | static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, |
1c57e86d EC |
3955 | struct CommandControlBlock *ccb) |
3956 | { | |
ae52e7f0 | 3957 | int rtn; |
ae52e7f0 | 3958 | rtn = arcmsr_polling_ccbdone(acb, ccb); |
ae52e7f0 | 3959 | return rtn; |
1c57e86d EC |
3960 | } |
3961 | ||
3962 | static int arcmsr_abort(struct scsi_cmnd *cmd) | |
3963 | { | |
3964 | struct AdapterControlBlock *acb = | |
3965 | (struct AdapterControlBlock *)cmd->device->host->hostdata; | |
3966 | int i = 0; | |
ae52e7f0 | 3967 | int rtn = FAILED; |
cab5aece CH |
3968 | uint32_t intmask_org; |
3969 | ||
1c57e86d | 3970 | printk(KERN_NOTICE |
cab5aece | 3971 | "arcmsr%d: abort device command of scsi id = %d lun = %d\n", |
9cb78c16 | 3972 | acb->host->host_no, cmd->device->id, (u32)cmd->device->lun); |
ae52e7f0 | 3973 | acb->acb_flags |= ACB_F_ABORT; |
1c57e86d | 3974 | acb->num_aborts++; |
1c57e86d EC |
3975 | /* |
3976 | ************************************************ | |
3977 | ** the all interrupt service routine is locked | |
3978 | ** we need to handle it as soon as possible and exit | |
3979 | ************************************************ | |
3980 | */ | |
cab5aece CH |
3981 | if (!atomic_read(&acb->ccboutstandingcount)) { |
3982 | acb->acb_flags &= ~ACB_F_ABORT; | |
ae52e7f0 | 3983 | return rtn; |
cab5aece | 3984 | } |
1c57e86d | 3985 | |
cab5aece | 3986 | intmask_org = arcmsr_disable_outbound_ints(acb); |
1c57e86d EC |
3987 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { |
3988 | struct CommandControlBlock *ccb = acb->pccb_pool[i]; | |
3989 | if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { | |
ae52e7f0 NC |
3990 | ccb->startdone = ARCMSR_CCB_ABORTED; |
3991 | rtn = arcmsr_abort_one_cmd(acb, ccb); | |
1c57e86d EC |
3992 | break; |
3993 | } | |
3994 | } | |
ae52e7f0 | 3995 | acb->acb_flags &= ~ACB_F_ABORT; |
cab5aece | 3996 | arcmsr_enable_outbound_ints(acb, intmask_org); |
ae52e7f0 | 3997 | return rtn; |
1c57e86d EC |
3998 | } |
3999 | ||
4000 | static const char *arcmsr_info(struct Scsi_Host *host) | |
4001 | { | |
4002 | struct AdapterControlBlock *acb = | |
4003 | (struct AdapterControlBlock *) host->hostdata; | |
4004 | static char buf[256]; | |
4005 | char *type; | |
4006 | int raid6 = 1; | |
1c57e86d EC |
4007 | switch (acb->pdev->device) { |
4008 | case PCI_DEVICE_ID_ARECA_1110: | |
1a4f550a NC |
4009 | case PCI_DEVICE_ID_ARECA_1200: |
4010 | case PCI_DEVICE_ID_ARECA_1202: | |
1c57e86d EC |
4011 | case PCI_DEVICE_ID_ARECA_1210: |
4012 | raid6 = 0; | |
4013 | /*FALLTHRU*/ | |
4014 | case PCI_DEVICE_ID_ARECA_1120: | |
4015 | case PCI_DEVICE_ID_ARECA_1130: | |
4016 | case PCI_DEVICE_ID_ARECA_1160: | |
4017 | case PCI_DEVICE_ID_ARECA_1170: | |
1a4f550a | 4018 | case PCI_DEVICE_ID_ARECA_1201: |
7e315ffd | 4019 | case PCI_DEVICE_ID_ARECA_1203: |
1c57e86d EC |
4020 | case PCI_DEVICE_ID_ARECA_1220: |
4021 | case PCI_DEVICE_ID_ARECA_1230: | |
4022 | case PCI_DEVICE_ID_ARECA_1260: | |
4023 | case PCI_DEVICE_ID_ARECA_1270: | |
4024 | case PCI_DEVICE_ID_ARECA_1280: | |
4025 | type = "SATA"; | |
4026 | break; | |
5b37479a | 4027 | case PCI_DEVICE_ID_ARECA_1214: |
1c57e86d EC |
4028 | case PCI_DEVICE_ID_ARECA_1380: |
4029 | case PCI_DEVICE_ID_ARECA_1381: | |
4030 | case PCI_DEVICE_ID_ARECA_1680: | |
4031 | case PCI_DEVICE_ID_ARECA_1681: | |
cdd3cb15 | 4032 | case PCI_DEVICE_ID_ARECA_1880: |
aaa64f69 | 4033 | type = "SAS/SATA"; |
1c57e86d EC |
4034 | break; |
4035 | default: | |
aaa64f69 CH |
4036 | type = "unknown"; |
4037 | raid6 = 0; | |
1c57e86d EC |
4038 | break; |
4039 | } | |
aaa64f69 CH |
4040 | sprintf(buf, "Areca %s RAID Controller %s\narcmsr version %s\n", |
4041 | type, raid6 ? "(RAID6 capable)" : "", ARCMSR_DRIVER_VERSION); | |
1c57e86d EC |
4042 | return buf; |
4043 | } |