blob: ba33473b27a1bc7b715dfc3c4f2aaf2505ffb241 [file] [log] [blame]
Erich Chen1c57e862006-07-12 08:59:32 -07001/*
2*******************************************************************************
3** O.S : Linux
4** FILE NAME : arcmsr_hba.c
5** BY : Erich Chen
6** Description: SCSI RAID Device Driver for
7** ARECA RAID Host adapter
8*******************************************************************************
9** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
10**
11** Web site: www.areca.com.tw
Nick Cheng1a4f5502007-09-13 17:26:40 +080012** E-mail: support@areca.com.tw
Erich Chen1c57e862006-07-12 08:59:32 -070013**
14** This program is free software; you can redistribute it and/or modify
15** it under the terms of the GNU General Public License version 2 as
16** published by the Free Software Foundation.
17** This program is distributed in the hope that it will be useful,
18** but WITHOUT ANY WARRANTY; without even the implied warranty of
19** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20** GNU General Public License for more details.
21*******************************************************************************
22** Redistribution and use in source and binary forms, with or without
23** modification, are permitted provided that the following conditions
24** are met:
25** 1. Redistributions of source code must retain the above copyright
26** notice, this list of conditions and the following disclaimer.
27** 2. Redistributions in binary form must reproduce the above copyright
28** notice, this list of conditions and the following disclaimer in the
29** documentation and/or other materials provided with the distribution.
30** 3. The name of the author may not be used to endorse or promote products
31** derived from this software without specific prior written permission.
32**
33** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
34** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
36** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
37** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
38** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
40** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
42** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43*******************************************************************************
44** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
45** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
46*******************************************************************************
47*/
48#include <linux/module.h>
49#include <linux/reboot.h>
50#include <linux/spinlock.h>
51#include <linux/pci_ids.h>
52#include <linux/interrupt.h>
53#include <linux/moduleparam.h>
54#include <linux/errno.h>
55#include <linux/types.h>
56#include <linux/delay.h>
57#include <linux/dma-mapping.h>
58#include <linux/timer.h>
59#include <linux/pci.h>
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +080060#include <linux/aer.h>
Erich Chen1c57e862006-07-12 08:59:32 -070061#include <asm/dma.h>
62#include <asm/io.h>
63#include <asm/system.h>
64#include <asm/uaccess.h>
65#include <scsi/scsi_host.h>
66#include <scsi/scsi.h>
67#include <scsi/scsi_cmnd.h>
68#include <scsi/scsi_tcq.h>
69#include <scsi/scsi_device.h>
70#include <scsi/scsi_transport.h>
71#include <scsi/scsicam.h>
72#include "arcmsr.h"
Nick Chengae52e7f2010-06-18 15:39:12 +080073MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
74MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter");
Erich Chen1c57e862006-07-12 08:59:32 -070075MODULE_LICENSE("Dual BSD/GPL");
76MODULE_VERSION(ARCMSR_DRIVER_VERSION);
Nick Chengae52e7f2010-06-18 15:39:12 +080077static int sleeptime = 20;
78static int retrycount = 12;
79wait_queue_head_t wait_q;
Nick Cheng1a4f5502007-09-13 17:26:40 +080080static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
81 struct scsi_cmnd *cmd);
82static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
Erich Chen1c57e862006-07-12 08:59:32 -070083static int arcmsr_abort(struct scsi_cmnd *);
84static int arcmsr_bus_reset(struct scsi_cmnd *);
85static int arcmsr_bios_param(struct scsi_device *sdev,
Nick Cheng1a4f5502007-09-13 17:26:40 +080086 struct block_device *bdev, sector_t capacity, int *info);
87static int arcmsr_queue_command(struct scsi_cmnd *cmd,
88 void (*done) (struct scsi_cmnd *));
Erich Chen1c57e862006-07-12 08:59:32 -070089static int arcmsr_probe(struct pci_dev *pdev,
90 const struct pci_device_id *id);
91static void arcmsr_remove(struct pci_dev *pdev);
92static void arcmsr_shutdown(struct pci_dev *pdev);
93static void arcmsr_iop_init(struct AdapterControlBlock *acb);
94static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +080095static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
Erich Chen1c57e862006-07-12 08:59:32 -070096static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +080097static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
98static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
Nick Cheng36b83de2010-05-17 11:22:42 +080099static void arcmsr_request_device_map(unsigned long pacb);
100static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
101static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
102static void arcmsr_message_isr_bh_fn(struct work_struct *work);
Nick Chengae52e7f2010-06-18 15:39:12 +0800103static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
Nick Cheng36b83de2010-05-17 11:22:42 +0800104static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
105
Erich Chen1c57e862006-07-12 08:59:32 -0700106static const char *arcmsr_info(struct Scsi_Host *);
107static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800108static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
Mike Christiee881a172009-10-15 17:46:39 -0700109 int queue_depth, int reason)
Erich Chen1c57e862006-07-12 08:59:32 -0700110{
Mike Christiee881a172009-10-15 17:46:39 -0700111 if (reason != SCSI_QDEPTH_DEFAULT)
112 return -EOPNOTSUPP;
113
Erich Chen1c57e862006-07-12 08:59:32 -0700114 if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
115 queue_depth = ARCMSR_MAX_CMD_PERLUN;
116 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
117 return queue_depth;
118}
119
120static struct scsi_host_template arcmsr_scsi_host_template = {
121 .module = THIS_MODULE,
Nick Cheng36b83de2010-05-17 11:22:42 +0800122 .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +0800123 ARCMSR_DRIVER_VERSION,
Erich Chen1c57e862006-07-12 08:59:32 -0700124 .info = arcmsr_info,
125 .queuecommand = arcmsr_queue_command,
126 .eh_abort_handler = arcmsr_abort,
127 .eh_bus_reset_handler = arcmsr_bus_reset,
128 .bios_param = arcmsr_bios_param,
129 .change_queue_depth = arcmsr_adjust_disk_queue_depth,
Nick Chengae52e7f2010-06-18 15:39:12 +0800130 .can_queue = ARCMSR_MAX_FREECCB_NUM,
Erich Chen1c57e862006-07-12 08:59:32 -0700131 .this_id = ARCMSR_SCSI_INITIATOR_ID,
Nick Chengae52e7f2010-06-18 15:39:12 +0800132 .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES,
133 .max_sectors = ARCMSR_MAX_XFER_SECTORS_C,
Erich Chen1c57e862006-07-12 08:59:32 -0700134 .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
135 .use_clustering = ENABLE_CLUSTERING,
136 .shost_attrs = arcmsr_host_attrs,
137};
Erich Chen1c57e862006-07-12 08:59:32 -0700138static struct pci_device_id arcmsr_device_id_table[] = {
139 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
140 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
141 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
142 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
143 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
Nick Cheng1a4f5502007-09-13 17:26:40 +0800144 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)},
145 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},
146 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},
Erich Chen1c57e862006-07-12 08:59:32 -0700147 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
148 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
149 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
150 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
151 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
152 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
153 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},
154 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
155 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
156 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
Nick Chengae52e7f2010-06-18 15:39:12 +0800157 {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)},
Erich Chen1c57e862006-07-12 08:59:32 -0700158 {0, 0}, /* Terminating entry */
159};
160MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
161static struct pci_driver arcmsr_pci_driver = {
162 .name = "arcmsr",
163 .id_table = arcmsr_device_id_table,
164 .probe = arcmsr_probe,
165 .remove = arcmsr_remove,
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +0800166 .shutdown = arcmsr_shutdown,
Erich Chen1c57e862006-07-12 08:59:32 -0700167};
168
Nick Chengae52e7f2010-06-18 15:39:12 +0800169static void arcmsr_free_mu(struct AdapterControlBlock *acb)
170{
171 switch (acb->adapter_type) {
172 case ACB_ADAPTER_TYPE_A:
173 break;
174 case ACB_ADAPTER_TYPE_B:{
175 struct MessageUnit_B *reg = acb->pmuB;
176 dma_free_coherent(&acb->pdev->dev,
177 sizeof(struct MessageUnit_B),
178 reg, acb->dma_coherent_handle_hbb_mu);
179 }
180 }
181}
182
183static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
184{
185 struct pci_dev *pdev = acb->pdev;
186
187 switch (acb->adapter_type) {
188 case ACB_ADAPTER_TYPE_A:{
189 acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
190 if (!acb->pmuA) {
191 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
192 return false;
193 }
194 break;
195 }
196 case ACB_ADAPTER_TYPE_B:{
197 void __iomem *mem_base0, *mem_base1;
198 mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
199 if (!mem_base0) {
200 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
201 return false;
202 }
203 mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
204 if (!mem_base1) {
205 iounmap(mem_base0);
206 printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
207 return false;
208 }
209 acb->mem_base0 = mem_base0;
210 acb->mem_base1 = mem_base1;
211 }
212 }
213 return true;
214}
215
216static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
217{
218 switch (acb->adapter_type) {
219 case ACB_ADAPTER_TYPE_A:{
220 iounmap(acb->pmuA);
221 }
222 case ACB_ADAPTER_TYPE_B:{
223 iounmap(acb->mem_base0);
224 iounmap(acb->mem_base1);
225 }
226 }
227}
228
David Howells7d12e782006-10-05 14:55:46 +0100229static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
Erich Chen1c57e862006-07-12 08:59:32 -0700230{
231 irqreturn_t handle_state;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800232 struct AdapterControlBlock *acb = dev_id;
Erich Chen1c57e862006-07-12 08:59:32 -0700233
Erich Chen1c57e862006-07-12 08:59:32 -0700234 handle_state = arcmsr_interrupt(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700235 return handle_state;
236}
237
238static int arcmsr_bios_param(struct scsi_device *sdev,
239 struct block_device *bdev, sector_t capacity, int *geom)
240{
241 int ret, heads, sectors, cylinders, total_capacity;
242 unsigned char *buffer;/* return copy of block device's partition table */
243
244 buffer = scsi_bios_ptable(bdev);
245 if (buffer) {
246 ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
247 kfree(buffer);
248 if (ret != -1)
249 return ret;
250 }
251 total_capacity = capacity;
252 heads = 64;
253 sectors = 32;
254 cylinders = total_capacity / (heads * sectors);
255 if (cylinders > 1024) {
256 heads = 255;
257 sectors = 63;
258 cylinders = total_capacity / (heads * sectors);
259 }
260 geom[0] = heads;
261 geom[1] = sectors;
262 geom[2] = cylinders;
263 return 0;
264}
265
Nick Cheng1a4f5502007-09-13 17:26:40 +0800266static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -0700267{
268 struct pci_dev *pdev = acb->pdev;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800269 u16 dev_id;
270 pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
Nick Chengae52e7f2010-06-18 15:39:12 +0800271 acb->dev_id = dev_id;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800272 switch (dev_id) {
273 case 0x1201 : {
274 acb->adapter_type = ACB_ADAPTER_TYPE_B;
275 }
276 break;
Erich Chen1c57e862006-07-12 08:59:32 -0700277
Nick Cheng1a4f5502007-09-13 17:26:40 +0800278 default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
279 }
280}
281
Nick Chengae52e7f2010-06-18 15:39:12 +0800282static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800283{
Nick Chengae52e7f2010-06-18 15:39:12 +0800284 struct MessageUnit_A __iomem *reg = acb->pmuA;
285 uint32_t Index;
286 uint8_t Retries = 0x00;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800287
Nick Chengae52e7f2010-06-18 15:39:12 +0800288 do {
289 for (Index = 0; Index < 100; Index++) {
290 if (readl(&reg->outbound_intstatus) &
291 ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
292 writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
293 &reg->outbound_intstatus);
294 return 0x00;
295 }
296 msleep(10);
297 } /*max 1 seconds*/
298
299 } while (Retries++ < 20);/*max 20 sec*/
300 return 0xff;
301}
302
303static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
304{
305 struct MessageUnit_B *reg = acb->pmuB;
306 uint32_t Index;
307 uint8_t Retries = 0x00;
308
309 do {
310 for (Index = 0; Index < 100; Index++) {
311 if (readl(reg->iop2drv_doorbell)
312 & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
313 writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
314 , reg->iop2drv_doorbell);
315 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
316 return 0x00;
317 }
318 msleep(10);
319 } /*max 1 seconds*/
320
321 } while (Retries++ < 20);/*max 20 sec*/
322 return 0xff;
323}
324
325static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
326{
327 struct MessageUnit_A __iomem *reg = acb->pmuA;
328 int retry_count = 30;
329
330 writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
331 do {
332 if (!arcmsr_hba_wait_msgint_ready(acb))
333 break;
334 else {
335 retry_count--;
336 printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
337 timeout, retry count down = %d \n", acb->host->host_no, retry_count);
338 }
339 } while (retry_count != 0);
340}
341
342static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
343{
344 struct MessageUnit_B *reg = acb->pmuB;
345 int retry_count = 30;
346
347 writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
348 do {
349 if (!arcmsr_hbb_wait_msgint_ready(acb))
350 break;
351 else {
352 retry_count--;
353 printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
354 timeout,retry count down = %d \n", acb->host->host_no, retry_count);
355 }
356 } while (retry_count != 0);
357}
358
359static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
360{
Nick Cheng1a4f5502007-09-13 17:26:40 +0800361 switch (acb->adapter_type) {
362
363 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +0800364 arcmsr_flush_hba_cache(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800365 }
366 break;
367
368 case ACB_ADAPTER_TYPE_B: {
Nick Chengae52e7f2010-06-18 15:39:12 +0800369 arcmsr_flush_hbb_cache(acb);
370 }
371 }
372}
Nick Cheng1a4f5502007-09-13 17:26:40 +0800373
Nick Chengae52e7f2010-06-18 15:39:12 +0800374static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
375{
Nick Cheng1a4f5502007-09-13 17:26:40 +0800376 struct pci_dev *pdev = acb->pdev;
Nick Chengae52e7f2010-06-18 15:39:12 +0800377 switch (acb->adapter_type) {
378 case ACB_ADAPTER_TYPE_A: {
379
Nick Cheng1a4f5502007-09-13 17:26:40 +0800380 void *dma_coherent;
Nick Chengae52e7f2010-06-18 15:39:12 +0800381 dma_addr_t dma_coherent_handle;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800382 struct CommandControlBlock *ccb_tmp;
Nick Chengae52e7f2010-06-18 15:39:12 +0800383 int i = 0, j = 0;
384 dma_addr_t cdb_phyaddr;
385 unsigned long roundup_ccbsize = 0;
386 unsigned long max_xfer_len;
387 unsigned long max_sg_entrys;
388 uint32_t firm_config_version;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800389
Nick Chengae52e7f2010-06-18 15:39:12 +0800390 for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
391 for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
392 acb->devstate[i][j] = ARECA_RAID_GONE;
393
394 max_xfer_len = ARCMSR_MAX_XFER_LEN;
395 max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
396 firm_config_version = acb->firm_cfg_version;
397 if ((firm_config_version & 0xFF) >= 3) {
398 max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
399 max_sg_entrys = (max_xfer_len/4096);
400 }
401 acb->host->max_sectors = max_xfer_len/512;
402 acb->host->sg_tablesize = max_sg_entrys;
403 roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
404 acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
405 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
406 if (!dma_coherent) {
407 printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800408 return -ENOMEM;
Nick Chengae52e7f2010-06-18 15:39:12 +0800409 }
410 memset(dma_coherent, 0, acb->uncache_size);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800411 acb->dma_coherent = dma_coherent;
412 acb->dma_coherent_handle = dma_coherent_handle;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800413 ccb_tmp = (struct CommandControlBlock *)dma_coherent;
Nick Chengae52e7f2010-06-18 15:39:12 +0800414 acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800415 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
Nick Chengae52e7f2010-06-18 15:39:12 +0800416 cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
417 ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800418 acb->pccb_pool[i] = ccb_tmp;
Nick Chengae52e7f2010-06-18 15:39:12 +0800419 ccb_tmp->acb = acb;
420 INIT_LIST_HEAD(&ccb_tmp->list);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800421 list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
Nick Chengae52e7f2010-06-18 15:39:12 +0800422 ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
423 dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800424 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800425 break;
Al Virodb3a91f2007-10-29 05:08:38 +0000426 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800427 case ACB_ADAPTER_TYPE_B: {
Al Virodb3a91f2007-10-29 05:08:38 +0000428
Nick Chengae52e7f2010-06-18 15:39:12 +0800429 void *dma_coherent;
430 dma_addr_t dma_coherent_handle;
431 struct CommandControlBlock *ccb_tmp;
432 uint32_t cdb_phyaddr;
433 unsigned int roundup_ccbsize = 0;
434 unsigned long max_xfer_len;
435 unsigned long max_sg_entrys;
436 unsigned long firm_config_version;
437 unsigned long max_freeccb_num = 0;
438 int i = 0, j = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800439
Nick Chengae52e7f2010-06-18 15:39:12 +0800440 max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
441 max_xfer_len = ARCMSR_MAX_XFER_LEN;
442 max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
443 firm_config_version = acb->firm_cfg_version;
444 if ((firm_config_version & 0xFF) >= 3) {
445 max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
446 ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
447 max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/
448 }
449 acb->host->max_sectors = max_xfer_len / 512;
450 acb->host->sg_tablesize = max_sg_entrys;
451 roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+
452 (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
453 acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
454 dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
455 &dma_coherent_handle, GFP_KERNEL);
456
457 if (!dma_coherent) {
458 printk(KERN_NOTICE "DMA allocation failed...........................\n");
459 return -ENOMEM;
460 }
461 memset(dma_coherent, 0, acb->uncache_size);
462 acb->dma_coherent = dma_coherent;
463 acb->dma_coherent_handle = dma_coherent_handle;
464 ccb_tmp = (struct CommandControlBlock *)dma_coherent;
465 acb->vir2phy_offset = (unsigned long)dma_coherent -
466 (unsigned long)dma_coherent_handle;
467 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
468 cdb_phyaddr = dma_coherent_handle +
469 offsetof(struct CommandControlBlock, arcmsr_cdb);
470 ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
471 acb->pccb_pool[i] = ccb_tmp;
472 ccb_tmp->acb = acb;
473 INIT_LIST_HEAD(&ccb_tmp->list);
474 list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
475 ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp +
476 roundup_ccbsize);
477 dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
478 }
Nick Cheng1a4f5502007-09-13 17:26:40 +0800479 for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
480 for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
Nick Chengae52e7f2010-06-18 15:39:12 +0800481 acb->devstate[i][j] = ARECA_RAID_GONE;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800482 }
483 break;
Erich Chen1c57e862006-07-12 08:59:32 -0700484 }
Erich Chen1c57e862006-07-12 08:59:32 -0700485 return 0;
486}
Nick Cheng36b83de2010-05-17 11:22:42 +0800487static void arcmsr_message_isr_bh_fn(struct work_struct *work)
488{
489 struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh);
490
491 switch (acb->adapter_type) {
492 case ACB_ADAPTER_TYPE_A: {
493
494 struct MessageUnit_A __iomem *reg = acb->pmuA;
495 char *acb_dev_map = (char *)acb->device_map;
496 uint32_t __iomem *signature = (uint32_t __iomem *) (&reg->message_rwbuffer[0]);
497 char __iomem *devicemap = (char __iomem *) (&reg->message_rwbuffer[21]);
498 int target, lun;
499 struct scsi_device *psdev;
500 char diff;
501
502 atomic_inc(&acb->rq_map_token);
503 if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
504 for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
505 diff = (*acb_dev_map)^readb(devicemap);
506 if (diff != 0) {
507 char temp;
508 *acb_dev_map = readb(devicemap);
509 temp = *acb_dev_map;
510 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
511 if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
512 scsi_add_device(acb->host, 0, target, lun);
513 } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
514 psdev = scsi_device_lookup(acb->host, 0, target, lun);
515 if (psdev != NULL) {
516 scsi_remove_device(psdev);
517 scsi_device_put(psdev);
518 }
519 }
520 temp >>= 1;
521 diff >>= 1;
522 }
523 }
524 devicemap++;
525 acb_dev_map++;
526 }
527 }
528 break;
529 }
530
531 case ACB_ADAPTER_TYPE_B: {
532 struct MessageUnit_B *reg = acb->pmuB;
533 char *acb_dev_map = (char *)acb->device_map;
Nick Chengae52e7f2010-06-18 15:39:12 +0800534 uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->message_rwbuffer[0]);
535 char __iomem *devicemap = (char __iomem *)(&reg->message_rwbuffer[21]);
Nick Cheng36b83de2010-05-17 11:22:42 +0800536 int target, lun;
537 struct scsi_device *psdev;
538 char diff;
539
540 atomic_inc(&acb->rq_map_token);
541 if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
542 for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
543 diff = (*acb_dev_map)^readb(devicemap);
544 if (diff != 0) {
545 char temp;
546 *acb_dev_map = readb(devicemap);
547 temp = *acb_dev_map;
548 for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
549 if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
550 scsi_add_device(acb->host, 0, target, lun);
551 } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
552 psdev = scsi_device_lookup(acb->host, 0, target, lun);
553 if (psdev != NULL) {
554 scsi_remove_device(psdev);
555 scsi_device_put(psdev);
556 }
557 }
558 temp >>= 1;
559 diff >>= 1;
560 }
561 }
562 devicemap++;
563 acb_dev_map++;
564 }
565 }
566 }
567 }
568}
Erich Chen1c57e862006-07-12 08:59:32 -0700569
Nick Chengae52e7f2010-06-18 15:39:12 +0800570static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Erich Chen1c57e862006-07-12 08:59:32 -0700571{
572 struct Scsi_Host *host;
573 struct AdapterControlBlock *acb;
574 uint8_t bus, dev_fun;
575 int error;
576
577 error = pci_enable_device(pdev);
Nick Chengae52e7f2010-06-18 15:39:12 +0800578 if (error) {
579 return -ENODEV;
Erich Chen1c57e862006-07-12 08:59:32 -0700580 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800581 host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
582 if (!host) {
583 goto pci_disable_dev;
584 }
Yang Hongyang6a355282009-04-06 19:01:13 -0700585 error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
Erich Chen1c57e862006-07-12 08:59:32 -0700586 if (error) {
Yang Hongyang284901a2009-04-06 19:01:15 -0700587 error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
Erich Chen1c57e862006-07-12 08:59:32 -0700588 if (error) {
589 printk(KERN_WARNING
590 "scsi%d: No suitable DMA mask available\n",
591 host->host_no);
Nick Chengae52e7f2010-06-18 15:39:12 +0800592 goto scsi_host_release;
Erich Chen1c57e862006-07-12 08:59:32 -0700593 }
594 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800595 init_waitqueue_head(&wait_q);
Erich Chen1c57e862006-07-12 08:59:32 -0700596 bus = pdev->bus->number;
597 dev_fun = pdev->devfn;
Nick Chengae52e7f2010-06-18 15:39:12 +0800598 acb = (struct AdapterControlBlock *) host->hostdata;
599 memset(acb, 0, sizeof(struct AdapterControlBlock));
Erich Chen1c57e862006-07-12 08:59:32 -0700600 acb->pdev = pdev;
Nick Chengae52e7f2010-06-18 15:39:12 +0800601 acb->host = host;
Erich Chen1c57e862006-07-12 08:59:32 -0700602 host->max_lun = ARCMSR_MAX_TARGETLUN;
603 host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
604 host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
Erich Chen1c57e862006-07-12 08:59:32 -0700605 host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
606 host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
607 host->this_id = ARCMSR_SCSI_INITIATOR_ID;
608 host->unique_id = (bus << 8) | dev_fun;
Nick Chengae52e7f2010-06-18 15:39:12 +0800609 pci_set_drvdata(pdev, host);
610 pci_set_master(pdev);
Erich Chen1c57e862006-07-12 08:59:32 -0700611 error = pci_request_regions(pdev, "arcmsr");
Nick Cheng1a4f5502007-09-13 17:26:40 +0800612 if (error) {
Nick Chengae52e7f2010-06-18 15:39:12 +0800613 goto scsi_host_release;
Erich Chen1c57e862006-07-12 08:59:32 -0700614 }
Nick Chengae52e7f2010-06-18 15:39:12 +0800615 spin_lock_init(&acb->eh_lock);
616 spin_lock_init(&acb->ccblist_lock);
Erich Chen1c57e862006-07-12 08:59:32 -0700617 acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
618 ACB_F_MESSAGE_RQBUFFER_CLEARED |
619 ACB_F_MESSAGE_WQBUFFER_READED);
620 acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
621 INIT_LIST_HEAD(&acb->ccb_free_list);
Nick Chengae52e7f2010-06-18 15:39:12 +0800622 arcmsr_define_adapter_type(acb);
623 error = arcmsr_remap_pciregion(acb);
624 if (!error) {
625 goto pci_release_regs;
626 }
627 error = arcmsr_get_firmware_spec(acb);
628 if (!error) {
629 goto unmap_pci_region;
630 }
Erich Chen1c57e862006-07-12 08:59:32 -0700631 error = arcmsr_alloc_ccb_pool(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +0800632 if (error) {
633 goto free_hbb_mu;
634 }
Nick Cheng36b83de2010-05-17 11:22:42 +0800635 arcmsr_iop_init(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700636 error = scsi_add_host(host, &pdev->dev);
Nick Chengae52e7f2010-06-18 15:39:12 +0800637 if (error) {
638 goto RAID_controller_stop;
639 }
640 error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
641 if (error) {
642 goto scsi_host_remove;
643 }
644 host->irq = pdev->irq;
Erich Chen1c57e862006-07-12 08:59:32 -0700645 scsi_scan_host(host);
Nick Chengae52e7f2010-06-18 15:39:12 +0800646 INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
Nick Cheng36b83de2010-05-17 11:22:42 +0800647 atomic_set(&acb->rq_map_token, 16);
Nick Chengae52e7f2010-06-18 15:39:12 +0800648 atomic_set(&acb->ante_token_value, 16);
649 acb->fw_flag = FW_NORMAL;
Nick Cheng36b83de2010-05-17 11:22:42 +0800650 init_timer(&acb->eternal_timer);
Nick Chengae52e7f2010-06-18 15:39:12 +0800651 acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
Nick Cheng36b83de2010-05-17 11:22:42 +0800652 acb->eternal_timer.data = (unsigned long) acb;
653 acb->eternal_timer.function = &arcmsr_request_device_map;
654 add_timer(&acb->eternal_timer);
Nick Chengae52e7f2010-06-18 15:39:12 +0800655 if (arcmsr_alloc_sysfs_attr(acb))
656 goto out_free_sysfs;
Erich Chen1c57e862006-07-12 08:59:32 -0700657 return 0;
658 out_free_sysfs:
Nick Chengae52e7f2010-06-18 15:39:12 +0800659scsi_host_remove:
660 scsi_remove_host(host);
661RAID_controller_stop:
662 arcmsr_stop_adapter_bgrb(acb);
663 arcmsr_flush_adapter_cache(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700664 arcmsr_free_ccb_pool(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +0800665free_hbb_mu:
666 arcmsr_free_mu(acb);
667unmap_pci_region:
668 arcmsr_unmap_pciregion(acb);
669pci_release_regs:
Erich Chen1c57e862006-07-12 08:59:32 -0700670 pci_release_regions(pdev);
Nick Chengae52e7f2010-06-18 15:39:12 +0800671scsi_host_release:
Erich Chen1c57e862006-07-12 08:59:32 -0700672 scsi_host_put(host);
Nick Chengae52e7f2010-06-18 15:39:12 +0800673pci_disable_dev:
Erich Chen1c57e862006-07-12 08:59:32 -0700674 pci_disable_device(pdev);
Nick Chengae52e7f2010-06-18 15:39:12 +0800675 return -ENODEV;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800676}
677
Nick Cheng36b83de2010-05-17 11:22:42 +0800678static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800679{
Al Viro80da1ad2007-10-29 05:08:28 +0000680 struct MessageUnit_A __iomem *reg = acb->pmuA;
Erich Chen1c57e862006-07-12 08:59:32 -0700681
682 writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
Nick Cheng36b83de2010-05-17 11:22:42 +0800683 if (arcmsr_hba_wait_msgint_ready(acb)) {
Erich Chen1c57e862006-07-12 08:59:32 -0700684 printk(KERN_NOTICE
685 "arcmsr%d: wait 'abort all outstanding command' timeout \n"
686 , acb->host->host_no);
Nick Cheng36b83de2010-05-17 11:22:42 +0800687 return 0xff;
688 }
689 return 0x00;
Erich Chen1c57e862006-07-12 08:59:32 -0700690}
691
Nick Cheng36b83de2010-05-17 11:22:42 +0800692static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800693{
Al Viro80da1ad2007-10-29 05:08:28 +0000694 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800695
Nick Chengae52e7f2010-06-18 15:39:12 +0800696 writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
Nick Cheng36b83de2010-05-17 11:22:42 +0800697 if (arcmsr_hbb_wait_msgint_ready(acb)) {
Nick Cheng1a4f5502007-09-13 17:26:40 +0800698 printk(KERN_NOTICE
699 "arcmsr%d: wait 'abort all outstanding command' timeout \n"
700 , acb->host->host_no);
Nick Cheng36b83de2010-05-17 11:22:42 +0800701 return 0xff;
702 }
703 return 0x00;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800704}
705
Nick Cheng36b83de2010-05-17 11:22:42 +0800706static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800707{
Nick Cheng36b83de2010-05-17 11:22:42 +0800708 uint8_t rtnval = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800709 switch (acb->adapter_type) {
710 case ACB_ADAPTER_TYPE_A: {
Nick Cheng36b83de2010-05-17 11:22:42 +0800711 rtnval = arcmsr_abort_hba_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800712 }
713 break;
714
715 case ACB_ADAPTER_TYPE_B: {
Nick Cheng36b83de2010-05-17 11:22:42 +0800716 rtnval = arcmsr_abort_hbb_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800717 }
718 }
Nick Cheng36b83de2010-05-17 11:22:42 +0800719 return rtnval;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800720}
721
Nick Chengae52e7f2010-06-18 15:39:12 +0800722static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
723{
724 struct MessageUnit_B *reg = pacb->pmuB;
725
726 writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
727 if (arcmsr_hbb_wait_msgint_ready(pacb)) {
728 printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
729 return false;
730}
731 return true;
732}
733
Erich Chen1c57e862006-07-12 08:59:32 -0700734static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
735{
Erich Chen1c57e862006-07-12 08:59:32 -0700736 struct scsi_cmnd *pcmd = ccb->pcmd;
737
FUJITA Tomonorideff2622007-05-14 19:25:56 +0900738 scsi_dma_unmap(pcmd);
Nick Chengae52e7f2010-06-18 15:39:12 +0800739 }
Erich Chen1c57e862006-07-12 08:59:32 -0700740
Nick Chengae52e7f2010-06-18 15:39:12 +0800741static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
Erich Chen1c57e862006-07-12 08:59:32 -0700742{
743 struct AdapterControlBlock *acb = ccb->acb;
744 struct scsi_cmnd *pcmd = ccb->pcmd;
Nick Chengae52e7f2010-06-18 15:39:12 +0800745 unsigned long flags;
Erich Chen1c57e862006-07-12 08:59:32 -0700746
Nick Chengae52e7f2010-06-18 15:39:12 +0800747 atomic_dec(&acb->ccboutstandingcount);
Erich Chen1c57e862006-07-12 08:59:32 -0700748 arcmsr_pci_unmap_dma(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -0700749 ccb->startdone = ARCMSR_CCB_DONE;
750 ccb->ccb_flags = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +0800751 spin_lock_irqsave(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -0700752 list_add_tail(&ccb->list, &acb->ccb_free_list);
Nick Chengae52e7f2010-06-18 15:39:12 +0800753 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -0700754 pcmd->scsi_done(pcmd);
755}
756
Nick Cheng1a4f5502007-09-13 17:26:40 +0800757static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
758{
759
760 struct scsi_cmnd *pcmd = ccb->pcmd;
761 struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
762
763 pcmd->result = DID_OK << 16;
764 if (sensebuffer) {
765 int sense_data_length =
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900766 sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
767 ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
768 memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800769 memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
770 sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
771 sensebuffer->Valid = 1;
772 }
773}
774
775static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
776{
777 u32 orig_mask = 0;
778 switch (acb->adapter_type) {
779
780 case ACB_ADAPTER_TYPE_A : {
Al Viro80da1ad2007-10-29 05:08:28 +0000781 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +0800782 orig_mask = readl(&reg->outbound_intmask);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800783 writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
784 &reg->outbound_intmask);
785 }
786 break;
787
788 case ACB_ADAPTER_TYPE_B : {
Al Viro80da1ad2007-10-29 05:08:28 +0000789 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +0800790 orig_mask = readl(reg->iop2drv_doorbell_mask);
791 writel(0, reg->iop2drv_doorbell_mask);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800792 }
793 break;
794 }
795 return orig_mask;
796}
797
Nick Chengae52e7f2010-06-18 15:39:12 +0800798static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +0800799 struct CommandControlBlock *ccb, uint32_t flag_ccb)
800{
801
802 uint8_t id, lun;
803 id = ccb->pcmd->device->id;
804 lun = ccb->pcmd->device->lun;
805 if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
806 if (acb->devstate[id][lun] == ARECA_RAID_GONE)
807 acb->devstate[id][lun] = ARECA_RAID_GOOD;
808 ccb->pcmd->result = DID_OK << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800809 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800810 } else {
811 switch (ccb->arcmsr_cdb.DeviceStatus) {
812 case ARCMSR_DEV_SELECT_TIMEOUT: {
813 acb->devstate[id][lun] = ARECA_RAID_GONE;
814 ccb->pcmd->result = DID_NO_CONNECT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800815 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800816 }
817 break;
818
819 case ARCMSR_DEV_ABORTED:
820
821 case ARCMSR_DEV_INIT_FAIL: {
822 acb->devstate[id][lun] = ARECA_RAID_GONE;
823 ccb->pcmd->result = DID_BAD_TARGET << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800824 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800825 }
826 break;
827
828 case ARCMSR_DEV_CHECK_CONDITION: {
829 acb->devstate[id][lun] = ARECA_RAID_GOOD;
830 arcmsr_report_sense_info(ccb);
Nick Chengae52e7f2010-06-18 15:39:12 +0800831 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800832 }
833 break;
834
835 default:
836 printk(KERN_NOTICE
837 "arcmsr%d: scsi id = %d lun = %d"
838 " isr get command error done, "
839 "but got unknown DeviceStatus = 0x%x \n"
840 , acb->host->host_no
841 , id
842 , lun
843 , ccb->arcmsr_cdb.DeviceStatus);
844 acb->devstate[id][lun] = ARECA_RAID_GONE;
845 ccb->pcmd->result = DID_NO_CONNECT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800846 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800847 break;
848 }
849 }
850}
851
852static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
853
854{
855 struct CommandControlBlock *ccb;
Nick Chengae52e7f2010-06-18 15:39:12 +0800856 struct ARCMSR_CDB *arcmsr_cdb;
857 int id, lun;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800858
Nick Chengae52e7f2010-06-18 15:39:12 +0800859 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
860 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800861 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
862 if (ccb->startdone == ARCMSR_CCB_ABORTED) {
863 struct scsi_cmnd *abortcmd = ccb->pcmd;
864 if (abortcmd) {
Nick Chengae52e7f2010-06-18 15:39:12 +0800865 id = abortcmd->device->id;
866 lun = abortcmd->device->lun;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800867 abortcmd->result |= DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800868 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800869 printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
870 isr got aborted command \n", acb->host->host_no, ccb);
871 }
872 }
873 printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
874 done acb = '0x%p'"
875 "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
876 " ccboutstandingcount = %d \n"
877 , acb->host->host_no
878 , acb
879 , ccb
880 , ccb->acb
881 , ccb->startdone
882 , atomic_read(&acb->ccboutstandingcount));
883 }
Nick Cheng76d78302008-02-04 23:53:24 -0800884 else
Nick Cheng1a4f5502007-09-13 17:26:40 +0800885 arcmsr_report_ccb_state(acb, ccb, flag_ccb);
886}
887
888static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
889{
890 int i = 0;
891 uint32_t flag_ccb;
892
893 switch (acb->adapter_type) {
894
895 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +0000896 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800897 uint32_t outbound_intstatus;
Al Viro80da1ad2007-10-29 05:08:28 +0000898 outbound_intstatus = readl(&reg->outbound_intstatus) &
Nick Cheng1a4f5502007-09-13 17:26:40 +0800899 acb->outbound_int_enable;
900 /*clear and abort all outbound posted Q*/
901 writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
Al Viro80da1ad2007-10-29 05:08:28 +0000902 while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
Nick Cheng1a4f5502007-09-13 17:26:40 +0800903 && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
904 arcmsr_drain_donequeue(acb, flag_ccb);
905 }
906 }
907 break;
908
909 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +0000910 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800911 /*clear all outbound posted Q*/
912 for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
913 if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
914 writel(0, &reg->done_qbuffer[i]);
915 arcmsr_drain_donequeue(acb, flag_ccb);
916 }
917 writel(0, &reg->post_qbuffer[i]);
918 }
919 reg->doneq_index = 0;
920 reg->postq_index = 0;
921 }
922 break;
923 }
924}
Erich Chen1c57e862006-07-12 08:59:32 -0700925static void arcmsr_remove(struct pci_dev *pdev)
926{
927 struct Scsi_Host *host = pci_get_drvdata(pdev);
928 struct AdapterControlBlock *acb =
929 (struct AdapterControlBlock *) host->hostdata;
Erich Chen1c57e862006-07-12 08:59:32 -0700930 int poll_count = 0;
Erich Chen1c57e862006-07-12 08:59:32 -0700931 arcmsr_free_sysfs_attr(acb);
932 scsi_remove_host(host);
Nick Chengae52e7f2010-06-18 15:39:12 +0800933 scsi_host_put(host);
Nick Cheng36b83de2010-05-17 11:22:42 +0800934 flush_scheduled_work();
935 del_timer_sync(&acb->eternal_timer);
936 arcmsr_disable_outbound_ints(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700937 arcmsr_stop_adapter_bgrb(acb);
938 arcmsr_flush_adapter_cache(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700939 acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
940 acb->acb_flags &= ~ACB_F_IOP_INITED;
941
Nick Cheng1a4f5502007-09-13 17:26:40 +0800942 for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
Erich Chen1c57e862006-07-12 08:59:32 -0700943 if (!atomic_read(&acb->ccboutstandingcount))
944 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +0800945 arcmsr_interrupt(acb);/* FIXME: need spinlock */
Erich Chen1c57e862006-07-12 08:59:32 -0700946 msleep(25);
947 }
948
949 if (atomic_read(&acb->ccboutstandingcount)) {
950 int i;
951
952 arcmsr_abort_allcmd(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +0800953 arcmsr_done4abort_postqueue(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700954 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
955 struct CommandControlBlock *ccb = acb->pccb_pool[i];
956 if (ccb->startdone == ARCMSR_CCB_START) {
957 ccb->startdone = ARCMSR_CCB_ABORTED;
958 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +0800959 arcmsr_ccb_complete(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -0700960 }
961 }
962 }
Erich Chen1c57e862006-07-12 08:59:32 -0700963 free_irq(pdev->irq, acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700964 arcmsr_free_ccb_pool(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +0800965 arcmsr_free_mu(acb);
Erich Chen1c57e862006-07-12 08:59:32 -0700966 pci_release_regions(pdev);
Erich Chen1c57e862006-07-12 08:59:32 -0700967 pci_disable_device(pdev);
968 pci_set_drvdata(pdev, NULL);
969}
970
971static void arcmsr_shutdown(struct pci_dev *pdev)
972{
973 struct Scsi_Host *host = pci_get_drvdata(pdev);
974 struct AdapterControlBlock *acb =
975 (struct AdapterControlBlock *)host->hostdata;
Nick Cheng36b83de2010-05-17 11:22:42 +0800976 del_timer_sync(&acb->eternal_timer);
977 arcmsr_disable_outbound_ints(acb);
978 flush_scheduled_work();
Erich Chen1c57e862006-07-12 08:59:32 -0700979 arcmsr_stop_adapter_bgrb(acb);
980 arcmsr_flush_adapter_cache(acb);
981}
982
983static int arcmsr_module_init(void)
984{
985 int error = 0;
986
987 error = pci_register_driver(&arcmsr_pci_driver);
988 return error;
989}
990
991static void arcmsr_module_exit(void)
992{
993 pci_unregister_driver(&arcmsr_pci_driver);
994}
995module_init(arcmsr_module_init);
996module_exit(arcmsr_module_exit);
997
Nick Cheng36b83de2010-05-17 11:22:42 +0800998static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +0800999 u32 intmask_org)
Erich Chen1c57e862006-07-12 08:59:32 -07001000{
Erich Chen1c57e862006-07-12 08:59:32 -07001001 u32 mask;
1002
Nick Cheng1a4f5502007-09-13 17:26:40 +08001003 switch (acb->adapter_type) {
1004
1005 case ACB_ADAPTER_TYPE_A : {
Al Viro80da1ad2007-10-29 05:08:28 +00001006 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001007 mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
Nick Cheng36b83de2010-05-17 11:22:42 +08001008 ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
1009 ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001010 writel(mask, &reg->outbound_intmask);
1011 acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
1012 }
1013 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001014
Nick Cheng1a4f5502007-09-13 17:26:40 +08001015 case ACB_ADAPTER_TYPE_B : {
Al Viro80da1ad2007-10-29 05:08:28 +00001016 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng36b83de2010-05-17 11:22:42 +08001017 mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
1018 ARCMSR_IOP2DRV_DATA_READ_OK |
1019 ARCMSR_IOP2DRV_CDB_DONE |
1020 ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
Nick Chengae52e7f2010-06-18 15:39:12 +08001021 writel(mask, reg->iop2drv_doorbell_mask);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001022 acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
1023 }
Erich Chen1c57e862006-07-12 08:59:32 -07001024 }
1025}
1026
Nick Cheng76d78302008-02-04 23:53:24 -08001027static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07001028 struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
1029{
1030 struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
1031 int8_t *psge = (int8_t *)&arcmsr_cdb->u;
Al Viro80da1ad2007-10-29 05:08:28 +00001032 __le32 address_lo, address_hi;
Erich Chen1c57e862006-07-12 08:59:32 -07001033 int arccdbsize = 0x30;
Nick Chengae52e7f2010-06-18 15:39:12 +08001034 __le32 length = 0;
1035 int i, cdb_sgcount = 0;
1036 struct scatterlist *sg;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001037 int nseg;
Erich Chen1c57e862006-07-12 08:59:32 -07001038
1039 ccb->pcmd = pcmd;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001040 memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
Erich Chen1c57e862006-07-12 08:59:32 -07001041 arcmsr_cdb->Bus = 0;
1042 arcmsr_cdb->TargetID = pcmd->device->id;
1043 arcmsr_cdb->LUN = pcmd->device->lun;
1044 arcmsr_cdb->Function = 1;
1045 arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
Nick Chengae52e7f2010-06-18 15:39:12 +08001046 arcmsr_cdb->Context = 0;
Erich Chen1c57e862006-07-12 08:59:32 -07001047 memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
Erich Chen1c57e862006-07-12 08:59:32 -07001048
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001049 nseg = scsi_dma_map(pcmd);
Nick Chengae52e7f2010-06-18 15:39:12 +08001050 if (nseg > acb->host->sg_tablesize || nseg < 0)
Nick Cheng76d78302008-02-04 23:53:24 -08001051 return FAILED;
Erich Chen1c57e862006-07-12 08:59:32 -07001052 /* map stor port SG list to our iop SG List. */
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001053 scsi_for_each_sg(pcmd, sg, nseg, i) {
Erich Chen1c57e862006-07-12 08:59:32 -07001054 /* Get the physical address of the current data pointer */
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001055 length = cpu_to_le32(sg_dma_len(sg));
1056 address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
1057 address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
Erich Chen1c57e862006-07-12 08:59:32 -07001058 if (address_hi == 0) {
1059 struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
1060
1061 pdma_sg->address = address_lo;
1062 pdma_sg->length = length;
1063 psge += sizeof (struct SG32ENTRY);
1064 arccdbsize += sizeof (struct SG32ENTRY);
1065 } else {
1066 struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
1067
1068 pdma_sg->addresshigh = address_hi;
1069 pdma_sg->address = address_lo;
Al Viro6a7d26d2007-10-29 05:08:48 +00001070 pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
Erich Chen1c57e862006-07-12 08:59:32 -07001071 psge += sizeof (struct SG64ENTRY);
1072 arccdbsize += sizeof (struct SG64ENTRY);
1073 }
Erich Chen1c57e862006-07-12 08:59:32 -07001074 cdb_sgcount++;
1075 }
1076 arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001077 arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
Nick Chengae52e7f2010-06-18 15:39:12 +08001078 arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
Erich Chen1c57e862006-07-12 08:59:32 -07001079 if ( arccdbsize > 256)
1080 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
Nick Chengae52e7f2010-06-18 15:39:12 +08001081 if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) {
Erich Chen1c57e862006-07-12 08:59:32 -07001082 arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
1083 ccb->ccb_flags |= CCB_FLAG_WRITE;
1084 }
Nick Cheng76d78302008-02-04 23:53:24 -08001085 return SUCCESS;
Erich Chen1c57e862006-07-12 08:59:32 -07001086}
1087
1088static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
1089{
Nick Chengae52e7f2010-06-18 15:39:12 +08001090 uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
Erich Chen1c57e862006-07-12 08:59:32 -07001091 struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
Erich Chen1c57e862006-07-12 08:59:32 -07001092 atomic_inc(&acb->ccboutstandingcount);
1093 ccb->startdone = ARCMSR_CCB_START;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001094
1095 switch (acb->adapter_type) {
1096 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001097 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001098
1099 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
Nick Chengae52e7f2010-06-18 15:39:12 +08001100 writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
Erich Chen1c57e862006-07-12 08:59:32 -07001101 &reg->inbound_queueport);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001102 else {
Nick Chengae52e7f2010-06-18 15:39:12 +08001103 writel(shifted_cdb_phyaddr, &reg->inbound_queueport);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001104 }
1105 }
1106 break;
1107
1108 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001109 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001110 uint32_t ending_index, index = reg->postq_index;
1111
1112 ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
1113 writel(0, &reg->post_qbuffer[ending_index]);
1114 if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
Nick Chengae52e7f2010-06-18 15:39:12 +08001115 writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
Nick Cheng1a4f5502007-09-13 17:26:40 +08001116 &reg->post_qbuffer[index]);
1117 }
1118 else {
Nick Chengae52e7f2010-06-18 15:39:12 +08001119 writel(shifted_cdb_phyaddr, &reg->post_qbuffer[index]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001120 }
1121 index++;
1122 index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
1123 reg->postq_index = index;
Nick Chengae52e7f2010-06-18 15:39:12 +08001124 writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001125 }
1126 break;
1127 }
Erich Chen1c57e862006-07-12 08:59:32 -07001128}
1129
Nick Cheng1a4f5502007-09-13 17:26:40 +08001130static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001131{
Al Viro80da1ad2007-10-29 05:08:28 +00001132 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001133 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
1134 writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
Erich Chen1c57e862006-07-12 08:59:32 -07001135
Nick Cheng1a4f5502007-09-13 17:26:40 +08001136 if (arcmsr_hba_wait_msgint_ready(acb)) {
1137 printk(KERN_NOTICE
1138 "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
1139 , acb->host->host_no);
1140 }
1141}
1142
1143static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
1144{
Al Viro80da1ad2007-10-29 05:08:28 +00001145 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001146 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001147 writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001148
1149 if (arcmsr_hbb_wait_msgint_ready(acb)) {
1150 printk(KERN_NOTICE
1151 "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
1152 , acb->host->host_no);
Erich Chen1c57e862006-07-12 08:59:32 -07001153 }
1154}
1155
1156static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
1157{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001158 switch (acb->adapter_type) {
1159 case ACB_ADAPTER_TYPE_A: {
1160 arcmsr_stop_hba_bgrb(acb);
1161 }
1162 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001163
Nick Cheng1a4f5502007-09-13 17:26:40 +08001164 case ACB_ADAPTER_TYPE_B: {
1165 arcmsr_stop_hbb_bgrb(acb);
1166 }
1167 break;
1168 }
Erich Chen1c57e862006-07-12 08:59:32 -07001169}
1170
1171static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
1172{
Al Virodb3a91f2007-10-29 05:08:38 +00001173 switch (acb->adapter_type) {
1174 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +08001175 dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
Al Virodb3a91f2007-10-29 05:08:38 +00001176 iounmap(acb->pmuA);
Nick Chengae52e7f2010-06-18 15:39:12 +08001177 }
Al Virodb3a91f2007-10-29 05:08:38 +00001178 break;
Al Virodb3a91f2007-10-29 05:08:38 +00001179 case ACB_ADAPTER_TYPE_B: {
Nick Chengae52e7f2010-06-18 15:39:12 +08001180 dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
Al Virodb3a91f2007-10-29 05:08:38 +00001181 }
1182 }
Erich Chen1c57e862006-07-12 08:59:32 -07001183}
1184
Nick Cheng1a4f5502007-09-13 17:26:40 +08001185void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001186{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001187 switch (acb->adapter_type) {
1188 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001189 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001190 writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
1191 }
1192 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001193
Nick Cheng1a4f5502007-09-13 17:26:40 +08001194 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001195 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001196 writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001197 }
1198 break;
1199 }
1200}
1201
1202static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
1203{
1204 switch (acb->adapter_type) {
1205 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001206 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001207 /*
1208 ** push inbound doorbell tell iop, driver data write ok
1209 ** and wait reply on next hwinterrupt for next Qbuffer post
1210 */
1211 writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
1212 }
1213 break;
1214
1215 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001216 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001217 /*
1218 ** push inbound doorbell tell iop, driver data write ok
1219 ** and wait reply on next hwinterrupt for next Qbuffer post
1220 */
Nick Chengae52e7f2010-06-18 15:39:12 +08001221 writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001222 }
1223 break;
1224 }
1225}
1226
Al Viro80da1ad2007-10-29 05:08:28 +00001227struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001228{
Al Viro0c7eb2e2007-10-29 05:08:58 +00001229 struct QBUFFER __iomem *qbuffer = NULL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001230
1231 switch (acb->adapter_type) {
1232
1233 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001234 struct MessageUnit_A __iomem *reg = acb->pmuA;
1235 qbuffer = (struct QBUFFER __iomem *)&reg->message_rbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001236 }
1237 break;
1238
1239 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001240 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001241 qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001242 }
1243 break;
1244 }
1245 return qbuffer;
1246}
1247
Al Viro80da1ad2007-10-29 05:08:28 +00001248static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001249{
Al Viro0c7eb2e2007-10-29 05:08:58 +00001250 struct QBUFFER __iomem *pqbuffer = NULL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001251
1252 switch (acb->adapter_type) {
1253
1254 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00001255 struct MessageUnit_A __iomem *reg = acb->pmuA;
1256 pqbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001257 }
1258 break;
1259
1260 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00001261 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001262 pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001263 }
1264 break;
1265 }
1266 return pqbuffer;
1267}
1268
1269static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
1270{
Al Viro80da1ad2007-10-29 05:08:28 +00001271 struct QBUFFER __iomem *prbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001272 struct QBUFFER *pQbuffer;
Al Viro80da1ad2007-10-29 05:08:28 +00001273 uint8_t __iomem *iop_data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001274 int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
1275
1276 rqbuf_lastindex = acb->rqbuf_lastindex;
1277 rqbuf_firstindex = acb->rqbuf_firstindex;
1278 prbuffer = arcmsr_get_iop_rqbuffer(acb);
Al Viro80da1ad2007-10-29 05:08:28 +00001279 iop_data = (uint8_t __iomem *)prbuffer->data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001280 iop_len = prbuffer->data_len;
1281 my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
1282
1283 if (my_empty_len >= iop_len)
1284 {
1285 while (iop_len > 0) {
1286 pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
1287 memcpy(pQbuffer, iop_data,1);
1288 rqbuf_lastindex++;
1289 rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
1290 iop_data++;
1291 iop_len--;
1292 }
1293 acb->rqbuf_lastindex = rqbuf_lastindex;
1294 arcmsr_iop_message_read(acb);
1295 }
1296
1297 else {
1298 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
1299 }
1300}
1301
1302static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
1303{
1304 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
1305 if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
1306 uint8_t *pQbuffer;
Al Viro80da1ad2007-10-29 05:08:28 +00001307 struct QBUFFER __iomem *pwbuffer;
1308 uint8_t __iomem *iop_data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001309 int32_t allxfer_len = 0;
1310
1311 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
1312 pwbuffer = arcmsr_get_iop_wqbuffer(acb);
1313 iop_data = (uint8_t __iomem *)pwbuffer->data;
1314
1315 while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
1316 (allxfer_len < 124)) {
1317 pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
1318 memcpy(iop_data, pQbuffer, 1);
1319 acb->wqbuf_firstindex++;
1320 acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
1321 iop_data++;
1322 allxfer_len++;
1323 }
1324 pwbuffer->data_len = allxfer_len;
1325
1326 arcmsr_iop_message_wrote(acb);
1327 }
1328
1329 if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
1330 acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
1331 }
1332}
1333
1334static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
1335{
1336 uint32_t outbound_doorbell;
Al Viro80da1ad2007-10-29 05:08:28 +00001337 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001338
1339 outbound_doorbell = readl(&reg->outbound_doorbell);
1340 writel(outbound_doorbell, &reg->outbound_doorbell);
1341 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
1342 arcmsr_iop2drv_data_wrote_handle(acb);
1343 }
1344
1345 if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
1346 arcmsr_iop2drv_data_read_handle(acb);
1347 }
1348}
1349
1350static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
1351{
1352 uint32_t flag_ccb;
Al Viro80da1ad2007-10-29 05:08:28 +00001353 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001354
1355 while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
1356 arcmsr_drain_donequeue(acb, flag_ccb);
1357 }
1358}
1359
1360static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
1361{
1362 uint32_t index;
1363 uint32_t flag_ccb;
Al Viro80da1ad2007-10-29 05:08:28 +00001364 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001365
1366 index = reg->doneq_index;
1367
1368 while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
1369 writel(0, &reg->done_qbuffer[index]);
1370 arcmsr_drain_donequeue(acb, flag_ccb);
1371 index++;
1372 index %= ARCMSR_MAX_HBB_POSTQUEUE;
1373 reg->doneq_index = index;
1374 }
1375}
Nick Cheng36b83de2010-05-17 11:22:42 +08001376/*
1377**********************************************************************************
1378** Handle a message interrupt
1379**
1380** The only message interrupt we expect is in response to a query for the current adapter config.
1381** We want this in order to compare the drivemap so that we can detect newly-attached drives.
1382**********************************************************************************
1383*/
1384static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
1385{
1386 struct MessageUnit_A *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001387
Nick Cheng36b83de2010-05-17 11:22:42 +08001388 /*clear interrupt and message state*/
1389 writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
1390 schedule_work(&acb->arcmsr_do_message_isr_bh);
1391}
1392static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
1393{
1394 struct MessageUnit_B *reg = acb->pmuB;
1395
1396 /*clear interrupt and message state*/
Nick Chengae52e7f2010-06-18 15:39:12 +08001397 writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
Nick Cheng36b83de2010-05-17 11:22:42 +08001398 schedule_work(&acb->arcmsr_do_message_isr_bh);
1399}
Nick Cheng1a4f5502007-09-13 17:26:40 +08001400static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
1401{
1402 uint32_t outbound_intstatus;
Al Viro80da1ad2007-10-29 05:08:28 +00001403 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001404
Nick Cheng36b83de2010-05-17 11:22:42 +08001405 outbound_intstatus = readl(&reg->outbound_intstatus) &
Nick Cheng1a4f5502007-09-13 17:26:40 +08001406 acb->outbound_int_enable;
1407 if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) {
1408 return 1;
1409 }
Erich Chen1c57e862006-07-12 08:59:32 -07001410 writel(outbound_intstatus, &reg->outbound_intstatus);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001411 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
1412 arcmsr_hba_doorbell_isr(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001413 }
1414 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001415 arcmsr_hba_postqueue_isr(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001416 }
Nick Cheng36b83de2010-05-17 11:22:42 +08001417 if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
1418 /* messenger of "driver to iop commands" */
1419 arcmsr_hba_message_isr(acb);
1420 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001421 return 0;
1422}
1423
1424static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
1425{
1426 uint32_t outbound_doorbell;
Al Viro80da1ad2007-10-29 05:08:28 +00001427 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001428
Nick Chengae52e7f2010-06-18 15:39:12 +08001429 outbound_doorbell = readl(reg->iop2drv_doorbell) &
Nick Cheng1a4f5502007-09-13 17:26:40 +08001430 acb->outbound_int_enable;
1431 if (!outbound_doorbell)
1432 return 1;
1433
Nick Chengae52e7f2010-06-18 15:39:12 +08001434 writel(~outbound_doorbell, reg->iop2drv_doorbell);
Nick Cheng36b83de2010-05-17 11:22:42 +08001435 /*in case the last action of doorbell interrupt clearance is cached,
1436 this action can push HW to write down the clear bit*/
Nick Chengae52e7f2010-06-18 15:39:12 +08001437 readl(reg->iop2drv_doorbell);
1438 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001439 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
1440 arcmsr_iop2drv_data_wrote_handle(acb);
1441 }
1442 if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
1443 arcmsr_iop2drv_data_read_handle(acb);
1444 }
1445 if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
1446 arcmsr_hbb_postqueue_isr(acb);
1447 }
Nick Cheng36b83de2010-05-17 11:22:42 +08001448 if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
1449 /* messenger of "driver to iop commands" */
1450 arcmsr_hbb_message_isr(acb);
1451 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001452
1453 return 0;
1454}
1455
1456static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
1457{
1458 switch (acb->adapter_type) {
1459 case ACB_ADAPTER_TYPE_A: {
1460 if (arcmsr_handle_hba_isr(acb)) {
1461 return IRQ_NONE;
1462 }
1463 }
1464 break;
1465
1466 case ACB_ADAPTER_TYPE_B: {
1467 if (arcmsr_handle_hbb_isr(acb)) {
1468 return IRQ_NONE;
1469 }
1470 }
1471 break;
1472 }
Erich Chen1c57e862006-07-12 08:59:32 -07001473 return IRQ_HANDLED;
1474}
1475
1476static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
1477{
1478 if (acb) {
1479 /* stop adapter background rebuild */
1480 if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001481 uint32_t intmask_org;
Erich Chen1c57e862006-07-12 08:59:32 -07001482 acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001483 intmask_org = arcmsr_disable_outbound_ints(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07001484 arcmsr_stop_adapter_bgrb(acb);
1485 arcmsr_flush_adapter_cache(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001486 arcmsr_enable_outbound_ints(acb, intmask_org);
Erich Chen1c57e862006-07-12 08:59:32 -07001487 }
1488 }
1489}
1490
Nick Cheng1a4f5502007-09-13 17:26:40 +08001491void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001492{
Nick Cheng1a4f5502007-09-13 17:26:40 +08001493 int32_t wqbuf_firstindex, wqbuf_lastindex;
1494 uint8_t *pQbuffer;
Al Viro80da1ad2007-10-29 05:08:28 +00001495 struct QBUFFER __iomem *pwbuffer;
1496 uint8_t __iomem *iop_data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001497 int32_t allxfer_len = 0;
1498
1499 pwbuffer = arcmsr_get_iop_wqbuffer(acb);
1500 iop_data = (uint8_t __iomem *)pwbuffer->data;
1501 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
1502 acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
1503 wqbuf_firstindex = acb->wqbuf_firstindex;
1504 wqbuf_lastindex = acb->wqbuf_lastindex;
1505 while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
1506 pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
1507 memcpy(iop_data, pQbuffer, 1);
1508 wqbuf_firstindex++;
1509 wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
1510 iop_data++;
1511 allxfer_len++;
1512 }
1513 acb->wqbuf_firstindex = wqbuf_firstindex;
1514 pwbuffer->data_len = allxfer_len;
1515 arcmsr_iop_message_wrote(acb);
1516 }
1517}
1518
Nick Cheng36b83de2010-05-17 11:22:42 +08001519static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08001520 struct scsi_cmnd *cmd)
1521{
Erich Chen1c57e862006-07-12 08:59:32 -07001522 struct CMD_MESSAGE_FIELD *pcmdmessagefld;
1523 int retvalue = 0, transfer_len = 0;
1524 char *buffer;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001525 struct scatterlist *sg;
Erich Chen1c57e862006-07-12 08:59:32 -07001526 uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
1527 (uint32_t ) cmd->cmnd[6] << 16 |
1528 (uint32_t ) cmd->cmnd[7] << 8 |
1529 (uint32_t ) cmd->cmnd[8];
Nick Cheng1a4f5502007-09-13 17:26:40 +08001530 /* 4 bytes: Areca io control code */
Erich Chen1c57e862006-07-12 08:59:32 -07001531
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001532 sg = scsi_sglist(cmd);
Jens Axboe45711f12007-10-22 21:19:53 +02001533 buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001534 if (scsi_sg_count(cmd) > 1) {
1535 retvalue = ARCMSR_MESSAGE_FAIL;
1536 goto message_out;
Erich Chen1c57e862006-07-12 08:59:32 -07001537 }
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001538 transfer_len += sg->length;
1539
Erich Chen1c57e862006-07-12 08:59:32 -07001540 if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
1541 retvalue = ARCMSR_MESSAGE_FAIL;
1542 goto message_out;
1543 }
1544 pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
1545 switch(controlcode) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001546
Erich Chen1c57e862006-07-12 08:59:32 -07001547 case ARCMSR_MESSAGE_READ_RQBUFFER: {
Daniel Drake69e562c2008-02-20 13:29:05 +00001548 unsigned char *ver_addr;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001549 uint8_t *pQbuffer, *ptmpQbuffer;
1550 int32_t allxfer_len = 0;
Erich Chen1c57e862006-07-12 08:59:32 -07001551
Daniel Drake69e562c2008-02-20 13:29:05 +00001552 ver_addr = kmalloc(1032, GFP_ATOMIC);
1553 if (!ver_addr) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001554 retvalue = ARCMSR_MESSAGE_FAIL;
1555 goto message_out;
1556 }
Nick Cheng36b83de2010-05-17 11:22:42 +08001557
Daniel Drake69e562c2008-02-20 13:29:05 +00001558 ptmpQbuffer = ver_addr;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001559 while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
1560 && (allxfer_len < 1031)) {
1561 pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
1562 memcpy(ptmpQbuffer, pQbuffer, 1);
1563 acb->rqbuf_firstindex++;
1564 acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
1565 ptmpQbuffer++;
1566 allxfer_len++;
1567 }
1568 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
Erich Chen1c57e862006-07-12 08:59:32 -07001569
Al Viro80da1ad2007-10-29 05:08:28 +00001570 struct QBUFFER __iomem *prbuffer;
1571 uint8_t __iomem *iop_data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001572 int32_t iop_len;
1573
1574 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
1575 prbuffer = arcmsr_get_iop_rqbuffer(acb);
Al Viro80da1ad2007-10-29 05:08:28 +00001576 iop_data = prbuffer->data;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001577 iop_len = readl(&prbuffer->data_len);
1578 while (iop_len > 0) {
1579 acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
1580 acb->rqbuf_lastindex++;
1581 acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
1582 iop_data++;
1583 iop_len--;
Erich Chen1c57e862006-07-12 08:59:32 -07001584 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001585 arcmsr_iop_message_read(acb);
1586 }
Daniel Drake69e562c2008-02-20 13:29:05 +00001587 memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001588 pcmdmessagefld->cmdmessage.Length = allxfer_len;
Nick Chengae52e7f2010-06-18 15:39:12 +08001589 if (acb->fw_flag == FW_DEADLOCK) {
1590 pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
1591 } else {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001592 pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
Nick Chengae52e7f2010-06-18 15:39:12 +08001593 }
Daniel Drake69e562c2008-02-20 13:29:05 +00001594 kfree(ver_addr);
Erich Chen1c57e862006-07-12 08:59:32 -07001595 }
1596 break;
Erich Chen1c57e862006-07-12 08:59:32 -07001597
Nick Cheng1a4f5502007-09-13 17:26:40 +08001598 case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
Daniel Drake69e562c2008-02-20 13:29:05 +00001599 unsigned char *ver_addr;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001600 int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
1601 uint8_t *pQbuffer, *ptmpuserbuffer;
1602
Daniel Drake69e562c2008-02-20 13:29:05 +00001603 ver_addr = kmalloc(1032, GFP_ATOMIC);
1604 if (!ver_addr) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001605 retvalue = ARCMSR_MESSAGE_FAIL;
1606 goto message_out;
1607 }
Nick Chengae52e7f2010-06-18 15:39:12 +08001608 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001609 pcmdmessagefld->cmdmessage.ReturnCode =
1610 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Chengae52e7f2010-06-18 15:39:12 +08001611 } else {
1612 pcmdmessagefld->cmdmessage.ReturnCode =
1613 ARCMSR_MESSAGE_RETURNCODE_OK;
Nick Cheng36b83de2010-05-17 11:22:42 +08001614 }
Daniel Drake69e562c2008-02-20 13:29:05 +00001615 ptmpuserbuffer = ver_addr;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001616 user_len = pcmdmessagefld->cmdmessage.Length;
1617 memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
1618 wqbuf_lastindex = acb->wqbuf_lastindex;
1619 wqbuf_firstindex = acb->wqbuf_firstindex;
1620 if (wqbuf_lastindex != wqbuf_firstindex) {
1621 struct SENSE_DATA *sensebuffer =
1622 (struct SENSE_DATA *)cmd->sense_buffer;
1623 arcmsr_post_ioctldata2iop(acb);
1624 /* has error report sensedata */
1625 sensebuffer->ErrorCode = 0x70;
1626 sensebuffer->SenseKey = ILLEGAL_REQUEST;
1627 sensebuffer->AdditionalSenseLength = 0x0A;
1628 sensebuffer->AdditionalSenseCode = 0x20;
1629 sensebuffer->Valid = 1;
1630 retvalue = ARCMSR_MESSAGE_FAIL;
1631 } else {
1632 my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
1633 &(ARCMSR_MAX_QBUFFER - 1);
1634 if (my_empty_len >= user_len) {
1635 while (user_len > 0) {
1636 pQbuffer =
1637 &acb->wqbuffer[acb->wqbuf_lastindex];
1638 memcpy(pQbuffer, ptmpuserbuffer, 1);
1639 acb->wqbuf_lastindex++;
1640 acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
1641 ptmpuserbuffer++;
1642 user_len--;
1643 }
1644 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
1645 acb->acb_flags &=
1646 ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
1647 arcmsr_post_ioctldata2iop(acb);
1648 }
1649 } else {
1650 /* has error report sensedata */
Erich Chen1c57e862006-07-12 08:59:32 -07001651 struct SENSE_DATA *sensebuffer =
1652 (struct SENSE_DATA *)cmd->sense_buffer;
Erich Chen1c57e862006-07-12 08:59:32 -07001653 sensebuffer->ErrorCode = 0x70;
1654 sensebuffer->SenseKey = ILLEGAL_REQUEST;
1655 sensebuffer->AdditionalSenseLength = 0x0A;
1656 sensebuffer->AdditionalSenseCode = 0x20;
1657 sensebuffer->Valid = 1;
1658 retvalue = ARCMSR_MESSAGE_FAIL;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001659 }
Erich Chen1c57e862006-07-12 08:59:32 -07001660 }
Daniel Drake69e562c2008-02-20 13:29:05 +00001661 kfree(ver_addr);
Erich Chen1c57e862006-07-12 08:59:32 -07001662 }
1663 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001664
Erich Chen1c57e862006-07-12 08:59:32 -07001665 case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001666 uint8_t *pQbuffer = acb->rqbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001667 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
1668 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
1669 arcmsr_iop_message_read(acb);
1670 }
1671 acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
1672 acb->rqbuf_firstindex = 0;
1673 acb->rqbuf_lastindex = 0;
1674 memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
Nick Chengae52e7f2010-06-18 15:39:12 +08001675 if (acb->fw_flag == FW_DEADLOCK) {
1676 pcmdmessagefld->cmdmessage.ReturnCode =
1677 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
1678 } else {
1679 pcmdmessagefld->cmdmessage.ReturnCode =
1680 ARCMSR_MESSAGE_RETURNCODE_OK;
1681 }
Erich Chen1c57e862006-07-12 08:59:32 -07001682 }
1683 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001684
Erich Chen1c57e862006-07-12 08:59:32 -07001685 case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001686 uint8_t *pQbuffer = acb->wqbuffer;
Nick Chengae52e7f2010-06-18 15:39:12 +08001687 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001688 pcmdmessagefld->cmdmessage.ReturnCode =
1689 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Chengae52e7f2010-06-18 15:39:12 +08001690 } else {
1691 pcmdmessagefld->cmdmessage.ReturnCode =
1692 ARCMSR_MESSAGE_RETURNCODE_OK;
Nick Cheng36b83de2010-05-17 11:22:42 +08001693 }
Erich Chen1c57e862006-07-12 08:59:32 -07001694
Nick Cheng1a4f5502007-09-13 17:26:40 +08001695 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
1696 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
1697 arcmsr_iop_message_read(acb);
1698 }
1699 acb->acb_flags |=
1700 (ACB_F_MESSAGE_WQBUFFER_CLEARED |
1701 ACB_F_MESSAGE_WQBUFFER_READED);
1702 acb->wqbuf_firstindex = 0;
1703 acb->wqbuf_lastindex = 0;
1704 memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
Erich Chen1c57e862006-07-12 08:59:32 -07001705 }
1706 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001707
Erich Chen1c57e862006-07-12 08:59:32 -07001708 case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001709 uint8_t *pQbuffer;
Erich Chen1c57e862006-07-12 08:59:32 -07001710
Nick Cheng1a4f5502007-09-13 17:26:40 +08001711 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
1712 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
1713 arcmsr_iop_message_read(acb);
1714 }
1715 acb->acb_flags |=
1716 (ACB_F_MESSAGE_WQBUFFER_CLEARED
1717 | ACB_F_MESSAGE_RQBUFFER_CLEARED
1718 | ACB_F_MESSAGE_WQBUFFER_READED);
1719 acb->rqbuf_firstindex = 0;
1720 acb->rqbuf_lastindex = 0;
1721 acb->wqbuf_firstindex = 0;
1722 acb->wqbuf_lastindex = 0;
1723 pQbuffer = acb->rqbuffer;
1724 memset(pQbuffer, 0, sizeof(struct QBUFFER));
1725 pQbuffer = acb->wqbuffer;
1726 memset(pQbuffer, 0, sizeof(struct QBUFFER));
Nick Chengae52e7f2010-06-18 15:39:12 +08001727 if (acb->fw_flag == FW_DEADLOCK) {
1728 pcmdmessagefld->cmdmessage.ReturnCode =
1729 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
1730 } else {
1731 pcmdmessagefld->cmdmessage.ReturnCode =
1732 ARCMSR_MESSAGE_RETURNCODE_OK;
1733 }
Erich Chen1c57e862006-07-12 08:59:32 -07001734 }
1735 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001736
Erich Chen1c57e862006-07-12 08:59:32 -07001737 case ARCMSR_MESSAGE_RETURN_CODE_3F: {
Nick Chengae52e7f2010-06-18 15:39:12 +08001738 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001739 pcmdmessagefld->cmdmessage.ReturnCode =
1740 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Chengae52e7f2010-06-18 15:39:12 +08001741 } else {
1742 pcmdmessagefld->cmdmessage.ReturnCode =
1743 ARCMSR_MESSAGE_RETURNCODE_3F;
Erich Chen1c57e862006-07-12 08:59:32 -07001744 }
1745 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08001746 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001747 case ARCMSR_MESSAGE_SAY_HELLO: {
1748 int8_t *hello_string = "Hello! I am ARCMSR";
Nick Chengae52e7f2010-06-18 15:39:12 +08001749 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001750 pcmdmessagefld->cmdmessage.ReturnCode =
1751 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Chengae52e7f2010-06-18 15:39:12 +08001752 } else {
1753 pcmdmessagefld->cmdmessage.ReturnCode =
1754 ARCMSR_MESSAGE_RETURNCODE_OK;
Nick Cheng36b83de2010-05-17 11:22:42 +08001755 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001756 memcpy(pcmdmessagefld->messagedatabuffer, hello_string
1757 , (int16_t)strlen(hello_string));
Erich Chen1c57e862006-07-12 08:59:32 -07001758 }
1759 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001760
Erich Chen1c57e862006-07-12 08:59:32 -07001761 case ARCMSR_MESSAGE_SAY_GOODBYE:
Nick Chengae52e7f2010-06-18 15:39:12 +08001762 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001763 pcmdmessagefld->cmdmessage.ReturnCode =
1764 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Cheng36b83de2010-05-17 11:22:42 +08001765 }
Erich Chen1c57e862006-07-12 08:59:32 -07001766 arcmsr_iop_parking(acb);
1767 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001768
Erich Chen1c57e862006-07-12 08:59:32 -07001769 case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
Nick Chengae52e7f2010-06-18 15:39:12 +08001770 if (acb->fw_flag == FW_DEADLOCK) {
Nick Cheng36b83de2010-05-17 11:22:42 +08001771 pcmdmessagefld->cmdmessage.ReturnCode =
1772 ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
Nick Cheng36b83de2010-05-17 11:22:42 +08001773 }
Erich Chen1c57e862006-07-12 08:59:32 -07001774 arcmsr_flush_adapter_cache(acb);
1775 break;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001776
Erich Chen1c57e862006-07-12 08:59:32 -07001777 default:
1778 retvalue = ARCMSR_MESSAGE_FAIL;
1779 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001780 message_out:
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001781 sg = scsi_sglist(cmd);
1782 kunmap_atomic(buffer - sg->offset, KM_IRQ0);
Erich Chen1c57e862006-07-12 08:59:32 -07001783 return retvalue;
1784}
1785
1786static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
1787{
1788 struct list_head *head = &acb->ccb_free_list;
1789 struct CommandControlBlock *ccb = NULL;
Nick Chengae52e7f2010-06-18 15:39:12 +08001790 unsigned long flags;
1791 spin_lock_irqsave(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07001792 if (!list_empty(head)) {
1793 ccb = list_entry(head->next, struct CommandControlBlock, list);
Nick Chengae52e7f2010-06-18 15:39:12 +08001794 list_del_init(&ccb->list);
1795 } else {
1796 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
1797 return 0;
Erich Chen1c57e862006-07-12 08:59:32 -07001798 }
Nick Chengae52e7f2010-06-18 15:39:12 +08001799 spin_unlock_irqrestore(&acb->ccblist_lock, flags);
Erich Chen1c57e862006-07-12 08:59:32 -07001800 return ccb;
1801}
1802
1803static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
1804 struct scsi_cmnd *cmd)
1805{
1806 switch (cmd->cmnd[0]) {
1807 case INQUIRY: {
1808 unsigned char inqdata[36];
1809 char *buffer;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001810 struct scatterlist *sg;
Erich Chen1c57e862006-07-12 08:59:32 -07001811
1812 if (cmd->device->lun) {
1813 cmd->result = (DID_TIME_OUT << 16);
1814 cmd->scsi_done(cmd);
1815 return;
1816 }
1817 inqdata[0] = TYPE_PROCESSOR;
1818 /* Periph Qualifier & Periph Dev Type */
1819 inqdata[1] = 0;
1820 /* rem media bit & Dev Type Modifier */
1821 inqdata[2] = 0;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08001822 /* ISO, ECMA, & ANSI versions */
Erich Chen1c57e862006-07-12 08:59:32 -07001823 inqdata[4] = 31;
1824 /* length of additional data */
1825 strncpy(&inqdata[8], "Areca ", 8);
1826 /* Vendor Identification */
1827 strncpy(&inqdata[16], "RAID controller ", 16);
1828 /* Product Identification */
1829 strncpy(&inqdata[32], "R001", 4); /* Product Revision */
Erich Chen1c57e862006-07-12 08:59:32 -07001830
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001831 sg = scsi_sglist(cmd);
Jens Axboe45711f12007-10-22 21:19:53 +02001832 buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001833
Erich Chen1c57e862006-07-12 08:59:32 -07001834 memcpy(buffer, inqdata, sizeof(inqdata));
FUJITA Tomonorideff2622007-05-14 19:25:56 +09001835 sg = scsi_sglist(cmd);
1836 kunmap_atomic(buffer - sg->offset, KM_IRQ0);
Erich Chen1c57e862006-07-12 08:59:32 -07001837
Erich Chen1c57e862006-07-12 08:59:32 -07001838 cmd->scsi_done(cmd);
1839 }
1840 break;
1841 case WRITE_BUFFER:
1842 case READ_BUFFER: {
1843 if (arcmsr_iop_message_xfer(acb, cmd))
1844 cmd->result = (DID_ERROR << 16);
1845 cmd->scsi_done(cmd);
1846 }
1847 break;
1848 default:
1849 cmd->scsi_done(cmd);
1850 }
1851}
1852
1853static int arcmsr_queue_command(struct scsi_cmnd *cmd,
1854 void (* done)(struct scsi_cmnd *))
1855{
1856 struct Scsi_Host *host = cmd->device->host;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001857 struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
Erich Chen1c57e862006-07-12 08:59:32 -07001858 struct CommandControlBlock *ccb;
1859 int target = cmd->device->id;
1860 int lun = cmd->device->lun;
Nick Cheng36b83de2010-05-17 11:22:42 +08001861 uint8_t scsicmd = cmd->cmnd[0];
Erich Chen1c57e862006-07-12 08:59:32 -07001862 cmd->scsi_done = done;
1863 cmd->host_scribble = NULL;
1864 cmd->result = 0;
Nick Cheng36b83de2010-05-17 11:22:42 +08001865
1866 if ((scsicmd == SYNCHRONIZE_CACHE) || (scsicmd == SEND_DIAGNOSTIC)) {
1867 if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
1868 cmd->result = (DID_NO_CONNECT << 16);
1869 }
1870 cmd->scsi_done(cmd);
1871 return 0;
1872 }
1873
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08001874 if (target == 16) {
Erich Chen1c57e862006-07-12 08:59:32 -07001875 /* virtual device for iop message transfer */
1876 arcmsr_handle_virtual_command(acb, cmd);
1877 return 0;
1878 }
Erich Chen1c57e862006-07-12 08:59:32 -07001879
Erich Chen1c57e862006-07-12 08:59:32 -07001880 if (atomic_read(&acb->ccboutstandingcount) >=
1881 ARCMSR_MAX_OUTSTANDING_CMD)
1882 return SCSI_MLQUEUE_HOST_BUSY;
1883
1884 ccb = arcmsr_get_freeccb(acb);
1885 if (!ccb)
1886 return SCSI_MLQUEUE_HOST_BUSY;
Nick Cheng76d78302008-02-04 23:53:24 -08001887 if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
1888 cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
1889 cmd->scsi_done(cmd);
1890 return 0;
1891 }
Erich Chen1c57e862006-07-12 08:59:32 -07001892 arcmsr_post_ccb(acb, ccb);
1893 return 0;
1894}
1895
Nick Chengae52e7f2010-06-18 15:39:12 +08001896static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07001897{
Al Viro80da1ad2007-10-29 05:08:28 +00001898 struct MessageUnit_A __iomem *reg = acb->pmuA;
Erich Chen1c57e862006-07-12 08:59:32 -07001899 char *acb_firm_model = acb->firm_model;
1900 char *acb_firm_version = acb->firm_version;
Nick Cheng36b83de2010-05-17 11:22:42 +08001901 char *acb_device_map = acb->device_map;
Al Viro80da1ad2007-10-29 05:08:28 +00001902 char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
1903 char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
Nick Cheng36b83de2010-05-17 11:22:42 +08001904 char __iomem *iop_device_map = (char __iomem *) (&reg->message_rwbuffer[21]);
Erich Chen1c57e862006-07-12 08:59:32 -07001905 int count;
1906
1907 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001908 if (arcmsr_hba_wait_msgint_ready(acb)) {
1909 printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
1910 miscellaneous data' timeout \n", acb->host->host_no);
Nick Chengae52e7f2010-06-18 15:39:12 +08001911 return false;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001912 }
Erich Chen1c57e862006-07-12 08:59:32 -07001913 count = 8;
1914 while (count) {
1915 *acb_firm_model = readb(iop_firm_model);
1916 acb_firm_model++;
1917 iop_firm_model++;
1918 count--;
1919 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001920
Erich Chen1c57e862006-07-12 08:59:32 -07001921 count = 16;
1922 while (count) {
1923 *acb_firm_version = readb(iop_firm_version);
1924 acb_firm_version++;
1925 iop_firm_version++;
1926 count--;
1927 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001928
Nick Cheng36b83de2010-05-17 11:22:42 +08001929 count = 16;
1930 while (count) {
1931 *acb_device_map = readb(iop_device_map);
1932 acb_device_map++;
1933 iop_device_map++;
1934 count--;
1935 }
Nick Chengae52e7f2010-06-18 15:39:12 +08001936 printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
1937 acb->host->host_no,
1938 acb->firm_version,
1939 acb->firm_model);
Nick Cheng36b83de2010-05-17 11:22:42 +08001940 acb->signature = readl(&reg->message_rwbuffer[0]);
Erich Chen1c57e862006-07-12 08:59:32 -07001941 acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
1942 acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
1943 acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
1944 acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
Nick Chengae52e7f2010-06-18 15:39:12 +08001945 acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
1946 return true;
Erich Chen1c57e862006-07-12 08:59:32 -07001947}
Nick Chengae52e7f2010-06-18 15:39:12 +08001948static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08001949{
Al Viro80da1ad2007-10-29 05:08:28 +00001950 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08001951 struct pci_dev *pdev = acb->pdev;
1952 void *dma_coherent;
1953 dma_addr_t dma_coherent_handle;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001954 char *acb_firm_model = acb->firm_model;
1955 char *acb_firm_version = acb->firm_version;
Nick Cheng36b83de2010-05-17 11:22:42 +08001956 char *acb_device_map = acb->device_map;
Nick Chengae52e7f2010-06-18 15:39:12 +08001957 char __iomem *iop_firm_model;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001958 /*firm_model,15,60-67*/
Nick Chengae52e7f2010-06-18 15:39:12 +08001959 char __iomem *iop_firm_version;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001960 /*firm_version,17,68-83*/
Nick Chengae52e7f2010-06-18 15:39:12 +08001961 char __iomem *iop_device_map;
Nick Cheng36b83de2010-05-17 11:22:42 +08001962 /*firm_version,21,84-99*/
Nick Cheng1a4f5502007-09-13 17:26:40 +08001963 int count;
Nick Chengae52e7f2010-06-18 15:39:12 +08001964 dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL);
1965 if (!dma_coherent) {
1966 printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no);
1967 return false;
1968 }
1969 acb->dma_coherent_handle_hbb_mu = dma_coherent_handle;
1970 reg = (struct MessageUnit_B *)dma_coherent;
1971 acb->pmuB = reg;
1972 reg->drv2iop_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
1973 reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
1974 reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
1975 reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
1976 reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
1977 reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
1978 reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
1979 iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
1980 iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
1981 iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
Nick Cheng1a4f5502007-09-13 17:26:40 +08001982
Nick Chengae52e7f2010-06-18 15:39:12 +08001983 writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08001984 if (arcmsr_hbb_wait_msgint_ready(acb)) {
1985 printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
1986 miscellaneous data' timeout \n", acb->host->host_no);
Nick Chengae52e7f2010-06-18 15:39:12 +08001987 return false;
Nick Cheng1a4f5502007-09-13 17:26:40 +08001988 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001989 count = 8;
Nick Chengae52e7f2010-06-18 15:39:12 +08001990 while (count) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001991 *acb_firm_model = readb(iop_firm_model);
1992 acb_firm_model++;
1993 iop_firm_model++;
1994 count--;
1995 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08001996 count = 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08001997 while (count) {
Nick Cheng1a4f5502007-09-13 17:26:40 +08001998 *acb_firm_version = readb(iop_firm_version);
1999 acb_firm_version++;
2000 iop_firm_version++;
2001 count--;
2002 }
2003
Nick Cheng36b83de2010-05-17 11:22:42 +08002004 count = 16;
2005 while (count) {
2006 *acb_device_map = readb(iop_device_map);
2007 acb_device_map++;
2008 iop_device_map++;
2009 count--;
2010 }
2011
Nick Chengae52e7f2010-06-18 15:39:12 +08002012 printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
Nick Cheng1a4f5502007-09-13 17:26:40 +08002013 acb->host->host_no,
Nick Chengae52e7f2010-06-18 15:39:12 +08002014 acb->firm_version,
2015 acb->firm_model);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002016
Nick Chengae52e7f2010-06-18 15:39:12 +08002017 acb->signature = readl(&reg->message_rwbuffer[1]);
Nick Cheng36b83de2010-05-17 11:22:42 +08002018 /*firm_signature,1,00-03*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002019 acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002020 /*firm_request_len,1,04-07*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002021 acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002022 /*firm_numbers_queue,2,08-11*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002023 acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002024 /*firm_sdram_size,3,12-15*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002025 acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002026 /*firm_ide_channels,4,16-19*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002027 acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
2028 /*firm_ide_channels,4,16-19*/
2029 return true;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002030}
Nick Chengae52e7f2010-06-18 15:39:12 +08002031static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
Nick Cheng1a4f5502007-09-13 17:26:40 +08002032{
Nick Chengae52e7f2010-06-18 15:39:12 +08002033 if (acb->adapter_type == ACB_ADAPTER_TYPE_A)
2034 return arcmsr_get_hba_config(acb);
2035 else
2036 return arcmsr_get_hbb_config(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002037}
2038
Nick Chengae52e7f2010-06-18 15:39:12 +08002039static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07002040 struct CommandControlBlock *poll_ccb)
2041{
Al Viro80da1ad2007-10-29 05:08:28 +00002042 struct MessageUnit_A __iomem *reg = acb->pmuA;
Erich Chen1c57e862006-07-12 08:59:32 -07002043 struct CommandControlBlock *ccb;
Nick Chengae52e7f2010-06-18 15:39:12 +08002044 struct ARCMSR_CDB *arcmsr_cdb;
Erich Chen1c57e862006-07-12 08:59:32 -07002045 uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08002046 int rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002047
Nick Cheng1a4f5502007-09-13 17:26:40 +08002048 polling_hba_ccb_retry:
Erich Chen1c57e862006-07-12 08:59:32 -07002049 poll_count++;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002050 outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
Erich Chen1c57e862006-07-12 08:59:32 -07002051 writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
2052 while (1) {
2053 if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002054 if (poll_ccb_done) {
2055 rtn = SUCCESS;
Erich Chen1c57e862006-07-12 08:59:32 -07002056 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08002057 } else {
2058 if (poll_count > 100) {
2059 rtn = FAILED;
Erich Chen1c57e862006-07-12 08:59:32 -07002060 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08002061 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002062 goto polling_hba_ccb_retry;
Erich Chen1c57e862006-07-12 08:59:32 -07002063 }
2064 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002065 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
2066 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002067 poll_ccb_done = (ccb == poll_ccb) ? 1:0;
2068 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
2069 if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
2070 printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
Erich Chen1c57e862006-07-12 08:59:32 -07002071 " poll command abort successfully \n"
2072 , acb->host->host_no
2073 , ccb->pcmd->device->id
2074 , ccb->pcmd->device->lun
2075 , ccb);
2076 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08002077 arcmsr_ccb_complete(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07002078 continue;
2079 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002080 printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
2081 " command done ccb = '0x%p'"
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002082 "ccboutstandingcount = %d \n"
Erich Chen1c57e862006-07-12 08:59:32 -07002083 , acb->host->host_no
2084 , ccb
2085 , atomic_read(&acb->ccboutstandingcount));
2086 continue;
Nick Chengae52e7f2010-06-18 15:39:12 +08002087 } else {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002088 arcmsr_report_ccb_state(acb, ccb, flag_ccb);
2089 }
2090}
Nick Chengae52e7f2010-06-18 15:39:12 +08002091 return rtn;
2092}
Nick Cheng1a4f5502007-09-13 17:26:40 +08002093
Nick Chengae52e7f2010-06-18 15:39:12 +08002094static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08002095 struct CommandControlBlock *poll_ccb)
2096{
Al Viro80da1ad2007-10-29 05:08:28 +00002097 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002098 struct ARCMSR_CDB *arcmsr_cdb;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002099 struct CommandControlBlock *ccb;
2100 uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08002101 int index, rtn;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002102
2103 polling_hbb_ccb_retry:
2104 poll_count++;
2105 /* clear doorbell interrupt */
Nick Chengae52e7f2010-06-18 15:39:12 +08002106 writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002107 while (1) {
2108 index = reg->doneq_index;
2109 if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002110 if (poll_ccb_done) {
2111 rtn = SUCCESS;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002112 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08002113 } else {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002114 msleep(25);
Nick Chengae52e7f2010-06-18 15:39:12 +08002115 if (poll_count > 100) {
2116 rtn = FAILED;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002117 break;
Nick Chengae52e7f2010-06-18 15:39:12 +08002118 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002119 goto polling_hbb_ccb_retry;
Erich Chen1c57e862006-07-12 08:59:32 -07002120 }
Erich Chen1c57e862006-07-12 08:59:32 -07002121 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002122 writel(0, &reg->done_qbuffer[index]);
2123 index++;
2124 /*if last index number set it to 0 */
2125 index %= ARCMSR_MAX_HBB_POSTQUEUE;
2126 reg->doneq_index = index;
2127 /* check ifcommand done with no error*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002128 arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
2129 ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002130 poll_ccb_done = (ccb == poll_ccb) ? 1:0;
2131 if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
Nick Cheng76d78302008-02-04 23:53:24 -08002132 if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002133 printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
2134 " poll command abort successfully \n"
Nick Cheng1a4f5502007-09-13 17:26:40 +08002135 ,acb->host->host_no
2136 ,ccb->pcmd->device->id
2137 ,ccb->pcmd->device->lun
2138 ,ccb);
2139 ccb->pcmd->result = DID_ABORT << 16;
Nick Chengae52e7f2010-06-18 15:39:12 +08002140 arcmsr_ccb_complete(ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002141 continue;
2142 }
2143 printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
2144 " command done ccb = '0x%p'"
2145 "ccboutstandingcount = %d \n"
2146 , acb->host->host_no
2147 , ccb
2148 , atomic_read(&acb->ccboutstandingcount));
2149 continue;
Nick Chengae52e7f2010-06-18 15:39:12 +08002150 } else {
Nick Cheng1a4f5502007-09-13 17:26:40 +08002151 arcmsr_report_ccb_state(acb, ccb, flag_ccb);
Nick Chengae52e7f2010-06-18 15:39:12 +08002152 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002153 } /*drain reply FIFO*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002154 return rtn;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002155}
2156
Nick Chengae52e7f2010-06-18 15:39:12 +08002157static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
Nick Cheng1a4f5502007-09-13 17:26:40 +08002158 struct CommandControlBlock *poll_ccb)
2159{
Nick Chengae52e7f2010-06-18 15:39:12 +08002160 int rtn = 0;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002161 switch (acb->adapter_type) {
2162
2163 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +08002164 rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002165 }
2166 break;
2167
2168 case ACB_ADAPTER_TYPE_B: {
Nick Chengae52e7f2010-06-18 15:39:12 +08002169 rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07002170 }
2171 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002172 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002173}
Nick Cheng1a4f5502007-09-13 17:26:40 +08002174
2175static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002176{
Nick Chengae52e7f2010-06-18 15:39:12 +08002177 uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002178 dma_addr_t dma_coherent_handle;
2179 /*
2180 ********************************************************************
2181 ** here we need to tell iop 331 our freeccb.HighPart
2182 ** if freeccb.HighPart is not zero
2183 ********************************************************************
2184 */
2185 dma_coherent_handle = acb->dma_coherent_handle;
2186 cdb_phyaddr = (uint32_t)(dma_coherent_handle);
Nick Chengae52e7f2010-06-18 15:39:12 +08002187 cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002188 /*
2189 ***********************************************************************
2190 ** if adapter type B, set window of "post command Q"
2191 ***********************************************************************
2192 */
2193 switch (acb->adapter_type) {
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002194
Nick Cheng1a4f5502007-09-13 17:26:40 +08002195 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +08002196 if (cdb_phyaddr_hi32 != 0) {
Al Viro80da1ad2007-10-29 05:08:28 +00002197 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002198 uint32_t intmask_org;
2199 intmask_org = arcmsr_disable_outbound_ints(acb);
2200 writel(ARCMSR_SIGNATURE_SET_CONFIG, \
2201 &reg->message_rwbuffer[0]);
Nick Chengae52e7f2010-06-18 15:39:12 +08002202 writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002203 writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
2204 &reg->inbound_msgaddr0);
2205 if (arcmsr_hba_wait_msgint_ready(acb)) {
2206 printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
2207 part physical address timeout\n",
2208 acb->host->host_no);
2209 return 1;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002210 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002211 arcmsr_enable_outbound_ints(acb, intmask_org);
2212 }
2213 }
2214 break;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002215
Nick Cheng1a4f5502007-09-13 17:26:40 +08002216 case ACB_ADAPTER_TYPE_B: {
2217 unsigned long post_queue_phyaddr;
Al Viro80da1ad2007-10-29 05:08:28 +00002218 uint32_t __iomem *rwbuffer;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002219
Al Viro80da1ad2007-10-29 05:08:28 +00002220 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002221 uint32_t intmask_org;
2222 intmask_org = arcmsr_disable_outbound_ints(acb);
2223 reg->postq_index = 0;
2224 reg->doneq_index = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08002225 writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002226 if (arcmsr_hbb_wait_msgint_ready(acb)) {
2227 printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
2228 acb->host->host_no);
2229 return 1;
2230 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002231 post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu;
2232 rwbuffer = reg->message_rwbuffer;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002233 /* driver "set config" signature */
2234 writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
2235 /* normal should be zero */
Nick Chengae52e7f2010-06-18 15:39:12 +08002236 writel(cdb_phyaddr_hi32, rwbuffer++);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002237 /* postQ size (256 + 8)*4 */
2238 writel(post_queue_phyaddr, rwbuffer++);
2239 /* doneQ size (256 + 8)*4 */
2240 writel(post_queue_phyaddr + 1056, rwbuffer++);
2241 /* ccb maxQ size must be --> [(256 + 8)*4]*/
2242 writel(1056, rwbuffer);
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002243
Nick Chengae52e7f2010-06-18 15:39:12 +08002244 writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002245 if (arcmsr_hbb_wait_msgint_ready(acb)) {
2246 printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
2247 timeout \n",acb->host->host_no);
2248 return 1;
2249 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002250 arcmsr_hbb_enable_driver_mode(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002251 arcmsr_enable_outbound_ints(acb, intmask_org);
2252 }
2253 break;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002254 }
Nick Cheng1a4f5502007-09-13 17:26:40 +08002255 return 0;
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002256}
2257
Nick Cheng1a4f5502007-09-13 17:26:40 +08002258static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
2259{
2260 uint32_t firmware_state = 0;
2261
2262 switch (acb->adapter_type) {
2263
2264 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00002265 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002266 do {
2267 firmware_state = readl(&reg->outbound_msgaddr1);
2268 } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
2269 }
2270 break;
2271
2272 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00002273 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002274 do {
Nick Chengae52e7f2010-06-18 15:39:12 +08002275 firmware_state = readl(reg->iop2drv_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002276 } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
Nick Chengae52e7f2010-06-18 15:39:12 +08002277 writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002278 }
2279 break;
2280 }
2281}
2282
Nick Cheng36b83de2010-05-17 11:22:42 +08002283static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
2284{
2285 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Chengae52e7f2010-06-18 15:39:12 +08002286 if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
2287 return;
Nick Cheng36b83de2010-05-17 11:22:42 +08002288 } else {
Nick Chengae52e7f2010-06-18 15:39:12 +08002289 acb->fw_flag = FW_NORMAL;
2290 if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
Nick Cheng36b83de2010-05-17 11:22:42 +08002291 atomic_set(&acb->rq_map_token, 16);
2292 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002293 atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
2294 if (atomic_dec_and_test(&acb->rq_map_token))
2295 return;
Nick Cheng36b83de2010-05-17 11:22:42 +08002296 writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
Nick Chengae52e7f2010-06-18 15:39:12 +08002297 mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
Nick Cheng36b83de2010-05-17 11:22:42 +08002298 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002299 return;
2300}
2301
2302static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
2303{
2304 struct MessageUnit_B __iomem *reg = acb->pmuB;
2305
Nick Chengae52e7f2010-06-18 15:39:12 +08002306 if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
2307 return;
Nick Cheng36b83de2010-05-17 11:22:42 +08002308 } else {
Nick Chengae52e7f2010-06-18 15:39:12 +08002309 acb->fw_flag = FW_NORMAL;
2310 if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
Nick Cheng36b83de2010-05-17 11:22:42 +08002311 atomic_set(&acb->rq_map_token, 16);
2312 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002313 atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
2314 if (atomic_dec_and_test(&acb->rq_map_token))
2315 return;
2316 writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
2317 mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
Nick Cheng36b83de2010-05-17 11:22:42 +08002318 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002319 return;
2320}
2321
2322static void arcmsr_request_device_map(unsigned long pacb)
2323{
2324 struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
2325
2326 switch (acb->adapter_type) {
2327 case ACB_ADAPTER_TYPE_A: {
2328 arcmsr_request_hba_device_map(acb);
2329 }
2330 break;
2331 case ACB_ADAPTER_TYPE_B: {
2332 arcmsr_request_hbb_device_map(acb);
2333 }
2334 break;
2335 }
2336}
2337
Nick Cheng1a4f5502007-09-13 17:26:40 +08002338static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
2339{
Al Viro80da1ad2007-10-29 05:08:28 +00002340 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002341 acb->acb_flags |= ACB_F_MSG_START_BGRB;
2342 writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
2343 if (arcmsr_hba_wait_msgint_ready(acb)) {
2344 printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
2345 rebulid' timeout \n", acb->host->host_no);
2346 }
2347}
2348
2349static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
2350{
Al Viro80da1ad2007-10-29 05:08:28 +00002351 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002352 acb->acb_flags |= ACB_F_MSG_START_BGRB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002353 writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002354 if (arcmsr_hbb_wait_msgint_ready(acb)) {
2355 printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
2356 rebulid' timeout \n",acb->host->host_no);
2357 }
2358}
2359
2360static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
2361{
2362 switch (acb->adapter_type) {
2363 case ACB_ADAPTER_TYPE_A:
2364 arcmsr_start_hba_bgrb(acb);
2365 break;
2366 case ACB_ADAPTER_TYPE_B:
2367 arcmsr_start_hbb_bgrb(acb);
2368 break;
2369 }
2370}
2371
2372static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
2373{
2374 switch (acb->adapter_type) {
2375 case ACB_ADAPTER_TYPE_A: {
Al Viro80da1ad2007-10-29 05:08:28 +00002376 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002377 uint32_t outbound_doorbell;
2378 /* empty doorbell Qbuffer if door bell ringed */
2379 outbound_doorbell = readl(&reg->outbound_doorbell);
2380 /*clear doorbell interrupt */
2381 writel(outbound_doorbell, &reg->outbound_doorbell);
2382 writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
2383 }
2384 break;
2385
2386 case ACB_ADAPTER_TYPE_B: {
Al Viro80da1ad2007-10-29 05:08:28 +00002387 struct MessageUnit_B *reg = acb->pmuB;
Nick Cheng1a4f5502007-09-13 17:26:40 +08002388 /*clear interrupt and message state*/
Nick Chengae52e7f2010-06-18 15:39:12 +08002389 writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
2390 writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002391 /* let IOP know data has been read */
2392 }
2393 break;
2394 }
2395}
Erich Chen1c57e862006-07-12 08:59:32 -07002396
Nick Cheng76d78302008-02-04 23:53:24 -08002397static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
2398{
2399 switch (acb->adapter_type) {
2400 case ACB_ADAPTER_TYPE_A:
2401 return;
2402 case ACB_ADAPTER_TYPE_B:
2403 {
2404 struct MessageUnit_B *reg = acb->pmuB;
Nick Chengae52e7f2010-06-18 15:39:12 +08002405 writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
Nick Cheng76d78302008-02-04 23:53:24 -08002406 if(arcmsr_hbb_wait_msgint_ready(acb)) {
2407 printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
2408 return;
2409 }
2410 }
2411 break;
2412 }
2413 return;
2414}
2415
Nick Cheng36b83de2010-05-17 11:22:42 +08002416static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
2417{
2418 uint8_t value[64];
2419 int i;
Nick Chengae52e7f2010-06-18 15:39:12 +08002420 struct MessageUnit_A __iomem *reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +08002421
2422 /* backup pci config data */
Nick Chengae52e7f2010-06-18 15:39:12 +08002423 printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
Nick Cheng36b83de2010-05-17 11:22:42 +08002424 for (i = 0; i < 64; i++) {
2425 pci_read_config_byte(acb->pdev, i, &value[i]);
2426 }
2427 /* hardware reset signal */
Nick Chengae52e7f2010-06-18 15:39:12 +08002428 if ((acb->dev_id == 0x1680)) {
2429 writel(ARCMSR_ARC1680_BUS_RESET, &reg->reserved1[0]);
2430 } else {
Nick Cheng36b83de2010-05-17 11:22:42 +08002431 pci_write_config_byte(acb->pdev, 0x84, 0x20);
Nick Chengae52e7f2010-06-18 15:39:12 +08002432 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002433 msleep(1000);
2434 /* write back pci config data */
2435 for (i = 0; i < 64; i++) {
2436 pci_write_config_byte(acb->pdev, i, value[i]);
2437 }
2438 msleep(1000);
2439 return;
2440}
2441/*
2442****************************************************************************
2443****************************************************************************
2444*/
Nick Cheng36b83de2010-05-17 11:22:42 +08002445 int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
2446 {
2447 struct Scsi_Host *shost = NULL;
Nick Cheng36b83de2010-05-17 11:22:42 +08002448 int i, isleep;
2449
2450 shost = cmd->device->host;
Nick Cheng36b83de2010-05-17 11:22:42 +08002451 isleep = sleeptime / 10;
Nick Cheng36b83de2010-05-17 11:22:42 +08002452 if (isleep > 0) {
2453 for (i = 0; i < isleep; i++) {
2454 msleep(10000);
Nick Cheng36b83de2010-05-17 11:22:42 +08002455 }
2456 }
2457
2458 isleep = sleeptime % 10;
2459 if (isleep > 0) {
2460 msleep(isleep * 1000);
Nick Cheng36b83de2010-05-17 11:22:42 +08002461 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002462 return 0;
2463 }
Erich Chen1c57e862006-07-12 08:59:32 -07002464static void arcmsr_iop_init(struct AdapterControlBlock *acb)
2465{
Nick Cheng1a4f5502007-09-13 17:26:40 +08002466 uint32_t intmask_org;
Erich Chen1c57e862006-07-12 08:59:32 -07002467
Nick Cheng1a4f5502007-09-13 17:26:40 +08002468 /* disable all outbound interrupt */
2469 intmask_org = arcmsr_disable_outbound_ints(acb);
Nick Cheng76d78302008-02-04 23:53:24 -08002470 arcmsr_wait_firmware_ready(acb);
2471 arcmsr_iop_confirm(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002472 /*start background rebuild*/
2473 arcmsr_start_adapter_bgrb(acb);
2474 /* empty doorbell Qbuffer if door bell ringed */
2475 arcmsr_clear_doorbell_queue_buffer(acb);
Nick Cheng76d78302008-02-04 23:53:24 -08002476 arcmsr_enable_eoi_mode(acb);
Nick Cheng1a4f5502007-09-13 17:26:40 +08002477 /* enable outbound Post Queue,outbound doorbell Interrupt */
2478 arcmsr_enable_outbound_ints(acb, intmask_org);
Erich Chen1c57e862006-07-12 08:59:32 -07002479 acb->acb_flags |= ACB_F_IOP_INITED;
2480}
2481
Nick Cheng36b83de2010-05-17 11:22:42 +08002482static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
Erich Chen1c57e862006-07-12 08:59:32 -07002483{
Erich Chen1c57e862006-07-12 08:59:32 -07002484 struct CommandControlBlock *ccb;
2485 uint32_t intmask_org;
Nick Cheng36b83de2010-05-17 11:22:42 +08002486 uint8_t rtnval = 0x00;
Erich Chen1c57e862006-07-12 08:59:32 -07002487 int i = 0;
2488
2489 if (atomic_read(&acb->ccboutstandingcount) != 0) {
Erich Chen1c57e862006-07-12 08:59:32 -07002490 /* disable all outbound interrupt */
2491 intmask_org = arcmsr_disable_outbound_ints(acb);
Nick Cheng36b83de2010-05-17 11:22:42 +08002492 /* talk to iop 331 outstanding command aborted */
2493 rtnval = arcmsr_abort_allcmd(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07002494 /* clear all outbound posted Q */
Nick Cheng1a4f5502007-09-13 17:26:40 +08002495 arcmsr_done4abort_postqueue(acb);
Erich Chen1c57e862006-07-12 08:59:32 -07002496 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
2497 ccb = acb->pccb_pool[i];
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002498 if (ccb->startdone == ARCMSR_CCB_START) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002499 arcmsr_ccb_complete(ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07002500 }
2501 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002502 atomic_set(&acb->ccboutstandingcount, 0);
Erich Chen1c57e862006-07-12 08:59:32 -07002503 /* enable all outbound interrupt */
2504 arcmsr_enable_outbound_ints(acb, intmask_org);
Nick Cheng36b83de2010-05-17 11:22:42 +08002505 return rtnval;
Erich Chen1c57e862006-07-12 08:59:32 -07002506 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002507 return rtnval;
Erich Chen1c57e862006-07-12 08:59:32 -07002508}
2509
2510static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
2511{
2512 struct AdapterControlBlock *acb =
2513 (struct AdapterControlBlock *)cmd->device->host->hostdata;
Nick Chengae52e7f2010-06-18 15:39:12 +08002514 uint32_t intmask_org, outbound_doorbell;
2515 int retry_count = 0;
2516 int rtn = FAILED;
Erich Chen1c57e862006-07-12 08:59:32 -07002517
Nick Chengae52e7f2010-06-18 15:39:12 +08002518 acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
2519 printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \
2520 num_aborts = %d \n", acb->num_resets, acb->num_aborts);
Nick Cheng36b83de2010-05-17 11:22:42 +08002521 acb->num_resets++;
Nick Cheng36b83de2010-05-17 11:22:42 +08002522
Nick Cheng36b83de2010-05-17 11:22:42 +08002523 switch (acb->adapter_type) {
2524 case ACB_ADAPTER_TYPE_A: {
Nick Chengae52e7f2010-06-18 15:39:12 +08002525 if (acb->acb_flags & ACB_F_BUS_RESET) {
2526 long timeout;
2527 timeout = wait_event_timeout(wait_q,
2528 (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
2529 if (timeout) {
2530 return SUCCESS;
2531 }
2532 }
2533 acb->acb_flags |= ACB_F_BUS_RESET;
2534 if (arcmsr_iop_reset(acb)) {
2535 struct MessageUnit_A __iomem *reg;
2536 reg = acb->pmuA;
Nick Cheng36b83de2010-05-17 11:22:42 +08002537 arcmsr_hardware_reset(acb);
Nick Cheng36b83de2010-05-17 11:22:42 +08002538 acb->acb_flags &= ~ACB_F_IOP_INITED;
Nick Cheng36b83de2010-05-17 11:22:42 +08002539sleep_again:
2540 arcmsr_sleep_for_bus_reset(cmd);
Nick Chengae52e7f2010-06-18 15:39:12 +08002541 if ((readl(&reg->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
2542 printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
2543 retry=%d \n", acb->host->host_no, retry_count);
Nick Cheng36b83de2010-05-17 11:22:42 +08002544 if (retry_count > retrycount) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002545 acb->fw_flag = FW_DEADLOCK;
2546 printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
2547 RETRY TERMINATED!! \n", acb->host->host_no);
2548 return FAILED;
Nick Cheng36b83de2010-05-17 11:22:42 +08002549 }
2550 retry_count++;
2551 goto sleep_again;
2552 }
Nick Cheng36b83de2010-05-17 11:22:42 +08002553 acb->acb_flags |= ACB_F_IOP_INITED;
Nick Cheng36b83de2010-05-17 11:22:42 +08002554 /* disable all outbound interrupt */
2555 intmask_org = arcmsr_disable_outbound_ints(acb);
Nick Chengae52e7f2010-06-18 15:39:12 +08002556 arcmsr_get_firmware_spec(acb);
Nick Cheng36b83de2010-05-17 11:22:42 +08002557 arcmsr_start_adapter_bgrb(acb);
2558 /* clear Qbuffer if door bell ringed */
2559 outbound_doorbell = readl(&reg->outbound_doorbell);
2560 writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
2561 writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
2562 /* enable outbound Post Queue,outbound doorbell Interrupt */
2563 arcmsr_enable_outbound_ints(acb, intmask_org);
2564 atomic_set(&acb->rq_map_token, 16);
Nick Chengae52e7f2010-06-18 15:39:12 +08002565 atomic_set(&acb->ante_token_value, 16);
2566 acb->fw_flag = FW_NORMAL;
2567 init_timer(&acb->eternal_timer);
2568 acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
2569 acb->eternal_timer.data = (unsigned long) acb;
2570 acb->eternal_timer.function = &arcmsr_request_device_map;
2571 add_timer(&acb->eternal_timer);
2572 acb->acb_flags &= ~ACB_F_BUS_RESET;
2573 rtn = SUCCESS;
2574 printk(KERN_ERR "arcmsr: scsi eh bus reset succeeds\n");
2575 } else {
2576 acb->acb_flags &= ~ACB_F_BUS_RESET;
2577 if (atomic_read(&acb->rq_map_token) == 0) {
2578 atomic_set(&acb->rq_map_token, 16);
2579 atomic_set(&acb->ante_token_value, 16);
2580 acb->fw_flag = FW_NORMAL;
Nick Cheng36b83de2010-05-17 11:22:42 +08002581 init_timer(&acb->eternal_timer);
Nick Chengae52e7f2010-06-18 15:39:12 +08002582 acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
Nick Cheng36b83de2010-05-17 11:22:42 +08002583 acb->eternal_timer.data = (unsigned long) acb;
2584 acb->eternal_timer.function = &arcmsr_request_device_map;
2585 add_timer(&acb->eternal_timer);
Nick Chengae52e7f2010-06-18 15:39:12 +08002586 } else {
2587 atomic_set(&acb->rq_map_token, 16);
2588 atomic_set(&acb->ante_token_value, 16);
2589 acb->fw_flag = FW_NORMAL;
2590 mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
Nick Cheng36b83de2010-05-17 11:22:42 +08002591 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002592 rtn = SUCCESS;
Nick Cheng36b83de2010-05-17 11:22:42 +08002593 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002594 break;
Nick Cheng36b83de2010-05-17 11:22:42 +08002595 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002596 case ACB_ADAPTER_TYPE_B:{
2597 acb->acb_flags |= ACB_F_BUS_RESET;
2598 if (arcmsr_iop_reset(acb)) {
2599 acb->acb_flags &= ~ACB_F_BUS_RESET;
2600 rtn = FAILED;
Nick Cheng36b83de2010-05-17 11:22:42 +08002601 } else {
Erich Chen1c57e862006-07-12 08:59:32 -07002602 acb->acb_flags &= ~ACB_F_BUS_RESET;
Nick Chengae52e7f2010-06-18 15:39:12 +08002603 if (atomic_read(&acb->rq_map_token) == 0) {
2604 atomic_set(&acb->rq_map_token, 16);
2605 atomic_set(&acb->ante_token_value, 16);
2606 acb->fw_flag = FW_NORMAL;
2607 init_timer(&acb->eternal_timer);
2608 acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
2609 acb->eternal_timer.data = (unsigned long) acb;
2610 acb->eternal_timer.function = &arcmsr_request_device_map;
2611 add_timer(&acb->eternal_timer);
2612 } else {
2613 atomic_set(&acb->rq_map_token, 16);
2614 atomic_set(&acb->ante_token_value, 16);
2615 acb->fw_flag = FW_NORMAL;
2616 mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
2617 }
2618 rtn = SUCCESS;
Nick Cheng36b83de2010-05-17 11:22:42 +08002619 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002620 }
2621 }
2622 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002623}
2624
Nick Chengae52e7f2010-06-18 15:39:12 +08002625static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
Erich Chen1c57e862006-07-12 08:59:32 -07002626 struct CommandControlBlock *ccb)
2627{
Nick Chengae52e7f2010-06-18 15:39:12 +08002628 int rtn;
2629 spin_lock_irq(&acb->eh_lock);
2630 rtn = arcmsr_polling_ccbdone(acb, ccb);
2631 spin_unlock_irq(&acb->eh_lock);
2632 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002633}
2634
2635static int arcmsr_abort(struct scsi_cmnd *cmd)
2636{
2637 struct AdapterControlBlock *acb =
2638 (struct AdapterControlBlock *)cmd->device->host->hostdata;
2639 int i = 0;
Nick Chengae52e7f2010-06-18 15:39:12 +08002640 int rtn = FAILED;
Erich Chen1c57e862006-07-12 08:59:32 -07002641
2642 printk(KERN_NOTICE
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002643 "arcmsr%d: abort device command of scsi id = %d lun = %d \n",
Erich Chen1c57e862006-07-12 08:59:32 -07002644 acb->host->host_no, cmd->device->id, cmd->device->lun);
Nick Chengae52e7f2010-06-18 15:39:12 +08002645 acb->acb_flags |= ACB_F_ABORT;
Erich Chen1c57e862006-07-12 08:59:32 -07002646 acb->num_aborts++;
Erich Chen1c57e862006-07-12 08:59:32 -07002647 /*
2648 ************************************************
2649 ** the all interrupt service routine is locked
2650 ** we need to handle it as soon as possible and exit
2651 ************************************************
2652 */
2653 if (!atomic_read(&acb->ccboutstandingcount))
Nick Chengae52e7f2010-06-18 15:39:12 +08002654 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002655
2656 for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
2657 struct CommandControlBlock *ccb = acb->pccb_pool[i];
2658 if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
Nick Chengae52e7f2010-06-18 15:39:12 +08002659 ccb->startdone = ARCMSR_CCB_ABORTED;
2660 rtn = arcmsr_abort_one_cmd(acb, ccb);
Erich Chen1c57e862006-07-12 08:59:32 -07002661 break;
2662 }
2663 }
Nick Chengae52e7f2010-06-18 15:39:12 +08002664 acb->acb_flags &= ~ACB_F_ABORT;
2665 return rtn;
Erich Chen1c57e862006-07-12 08:59:32 -07002666}
2667
2668static const char *arcmsr_info(struct Scsi_Host *host)
2669{
2670 struct AdapterControlBlock *acb =
2671 (struct AdapterControlBlock *) host->hostdata;
2672 static char buf[256];
2673 char *type;
2674 int raid6 = 1;
2675
2676 switch (acb->pdev->device) {
2677 case PCI_DEVICE_ID_ARECA_1110:
Nick Cheng1a4f5502007-09-13 17:26:40 +08002678 case PCI_DEVICE_ID_ARECA_1200:
2679 case PCI_DEVICE_ID_ARECA_1202:
Erich Chen1c57e862006-07-12 08:59:32 -07002680 case PCI_DEVICE_ID_ARECA_1210:
2681 raid6 = 0;
2682 /*FALLTHRU*/
2683 case PCI_DEVICE_ID_ARECA_1120:
2684 case PCI_DEVICE_ID_ARECA_1130:
2685 case PCI_DEVICE_ID_ARECA_1160:
2686 case PCI_DEVICE_ID_ARECA_1170:
Nick Cheng1a4f5502007-09-13 17:26:40 +08002687 case PCI_DEVICE_ID_ARECA_1201:
Erich Chen1c57e862006-07-12 08:59:32 -07002688 case PCI_DEVICE_ID_ARECA_1220:
2689 case PCI_DEVICE_ID_ARECA_1230:
2690 case PCI_DEVICE_ID_ARECA_1260:
2691 case PCI_DEVICE_ID_ARECA_1270:
2692 case PCI_DEVICE_ID_ARECA_1280:
2693 type = "SATA";
2694 break;
2695 case PCI_DEVICE_ID_ARECA_1380:
2696 case PCI_DEVICE_ID_ARECA_1381:
2697 case PCI_DEVICE_ID_ARECA_1680:
2698 case PCI_DEVICE_ID_ARECA_1681:
2699 type = "SAS";
2700 break;
2701 default:
2702 type = "X-TYPE";
2703 break;
2704 }
nickcheng(鄭守謙a1f6e022007-06-15 11:43:32 +08002705 sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
Erich Chen1c57e862006-07-12 08:59:32 -07002706 type, raid6 ? "( RAID6 capable)" : "",
2707 ARCMSR_DRIVER_VERSION);
2708 return buf;
2709}