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