diff options
author | Erich Chen <erich@areca.com.tw> | 2006-07-12 11:59:32 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-07-28 15:13:40 -0400 |
commit | 1c57e86d75cf162bdadb3a5fe0cd3f65aa1a9ca3 (patch) | |
tree | 166f691c186d6e663218559c4762299063f63657 /drivers/scsi/arcmsr | |
parent | 0c269e6d3c615403a6e0acbe6e88f1c0da9c2396 (diff) |
[SCSI] arcmsr: initial driver, version 1.20.00.13
arcmsr is a driver for the Areca Raid controller, a host based RAID
subsystem that speaks SCSI at the firmware level.
This patch is quite a clean up over the initial submission with
contributions from:
Randy Dunlap <rdunlap@xenotime.net>
Christoph Hellwig <hch@lst.de>
Matthew Wilcox <matthew@wil.cx>
Adrian Bunk <bunk@stusta.de>
Signed-off-by: Erich Chen <erich@areca.com.tw>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/arcmsr')
-rw-r--r-- | drivers/scsi/arcmsr/Makefile | 6 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr.h | 472 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_attr.c | 392 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 1496 |
4 files changed, 2366 insertions, 0 deletions
diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile new file mode 100644 index 000000000000..721aced39168 --- /dev/null +++ b/drivers/scsi/arcmsr/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # File: drivers/arcmsr/Makefile | ||
2 | # Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver. | ||
3 | |||
4 | arcmsr-objs := arcmsr_attr.o arcmsr_hba.o | ||
5 | |||
6 | obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o | ||
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h new file mode 100644 index 000000000000..aff96db9ccf6 --- /dev/null +++ b/drivers/scsi/arcmsr/arcmsr.h | |||
@@ -0,0 +1,472 @@ | |||
1 | /* | ||
2 | ******************************************************************************* | ||
3 | ** O.S : Linux | ||
4 | ** FILE NAME : arcmsr.h | ||
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 | ||
12 | ** E-mail: erich@areca.com.tw | ||
13 | ** | ||
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 | */ | ||
45 | #include <linux/interrupt.h> | ||
46 | |||
47 | struct class_device_attribute; | ||
48 | |||
49 | #define ARCMSR_MAX_OUTSTANDING_CMD 256 | ||
50 | #define ARCMSR_MAX_FREECCB_NUM 288 | ||
51 | #define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13" | ||
52 | #define ARCMSR_SCSI_INITIATOR_ID 255 | ||
53 | #define ARCMSR_MAX_XFER_SECTORS 512 | ||
54 | #define ARCMSR_MAX_TARGETID 17 | ||
55 | #define ARCMSR_MAX_TARGETLUN 8 | ||
56 | #define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD | ||
57 | #define ARCMSR_MAX_QBUFFER 4096 | ||
58 | #define ARCMSR_MAX_SG_ENTRIES 38 | ||
59 | |||
60 | /* | ||
61 | ******************************************************************************* | ||
62 | ** split 64bits dma addressing | ||
63 | ******************************************************************************* | ||
64 | */ | ||
65 | #define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16) | ||
66 | #define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff) | ||
67 | /* | ||
68 | ******************************************************************************* | ||
69 | ** MESSAGE CONTROL CODE | ||
70 | ******************************************************************************* | ||
71 | */ | ||
72 | struct CMD_MESSAGE | ||
73 | { | ||
74 | uint32_t HeaderLength; | ||
75 | uint8_t Signature[8]; | ||
76 | uint32_t Timeout; | ||
77 | uint32_t ControlCode; | ||
78 | uint32_t ReturnCode; | ||
79 | uint32_t Length; | ||
80 | }; | ||
81 | /* | ||
82 | ******************************************************************************* | ||
83 | ** IOP Message Transfer Data for user space | ||
84 | ******************************************************************************* | ||
85 | */ | ||
86 | struct CMD_MESSAGE_FIELD | ||
87 | { | ||
88 | struct CMD_MESSAGE cmdmessage; | ||
89 | uint8_t messagedatabuffer[1032]; | ||
90 | }; | ||
91 | /* IOP message transfer */ | ||
92 | #define ARCMSR_MESSAGE_FAIL 0x0001 | ||
93 | /* DeviceType */ | ||
94 | #define ARECA_SATA_RAID 0x90000000 | ||
95 | /* FunctionCode */ | ||
96 | #define FUNCTION_READ_RQBUFFER 0x0801 | ||
97 | #define FUNCTION_WRITE_WQBUFFER 0x0802 | ||
98 | #define FUNCTION_CLEAR_RQBUFFER 0x0803 | ||
99 | #define FUNCTION_CLEAR_WQBUFFER 0x0804 | ||
100 | #define FUNCTION_CLEAR_ALLQBUFFER 0x0805 | ||
101 | #define FUNCTION_RETURN_CODE_3F 0x0806 | ||
102 | #define FUNCTION_SAY_HELLO 0x0807 | ||
103 | #define FUNCTION_SAY_GOODBYE 0x0808 | ||
104 | #define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809 | ||
105 | /* ARECA IO CONTROL CODE*/ | ||
106 | #define ARCMSR_MESSAGE_READ_RQBUFFER \ | ||
107 | ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER | ||
108 | #define ARCMSR_MESSAGE_WRITE_WQBUFFER \ | ||
109 | ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER | ||
110 | #define ARCMSR_MESSAGE_CLEAR_RQBUFFER \ | ||
111 | ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER | ||
112 | #define ARCMSR_MESSAGE_CLEAR_WQBUFFER \ | ||
113 | ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER | ||
114 | #define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER \ | ||
115 | ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER | ||
116 | #define ARCMSR_MESSAGE_RETURN_CODE_3F \ | ||
117 | ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F | ||
118 | #define ARCMSR_MESSAGE_SAY_HELLO \ | ||
119 | ARECA_SATA_RAID | FUNCTION_SAY_HELLO | ||
120 | #define ARCMSR_MESSAGE_SAY_GOODBYE \ | ||
121 | ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE | ||
122 | #define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \ | ||
123 | ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE | ||
124 | /* ARECA IOCTL ReturnCode */ | ||
125 | #define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 | ||
126 | #define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 | ||
127 | #define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F | ||
128 | /* | ||
129 | ************************************************************* | ||
130 | ** structure for holding DMA address data | ||
131 | ************************************************************* | ||
132 | */ | ||
133 | #define IS_SG64_ADDR 0x01000000 /* bit24 */ | ||
134 | struct SG32ENTRY | ||
135 | { | ||
136 | uint32_t length; | ||
137 | uint32_t address; | ||
138 | }; | ||
139 | struct SG64ENTRY | ||
140 | { | ||
141 | uint32_t length; | ||
142 | uint32_t address; | ||
143 | uint32_t addresshigh; | ||
144 | }; | ||
145 | struct SGENTRY_UNION | ||
146 | { | ||
147 | union | ||
148 | { | ||
149 | struct SG32ENTRY sg32entry; | ||
150 | struct SG64ENTRY sg64entry; | ||
151 | }u; | ||
152 | }; | ||
153 | /* | ||
154 | ******************************************************************** | ||
155 | ** Q Buffer of IOP Message Transfer | ||
156 | ******************************************************************** | ||
157 | */ | ||
158 | struct QBUFFER | ||
159 | { | ||
160 | uint32_t data_len; | ||
161 | uint8_t data[124]; | ||
162 | }; | ||
163 | /* | ||
164 | ******************************************************************************* | ||
165 | ** FIRMWARE INFO | ||
166 | ******************************************************************************* | ||
167 | */ | ||
168 | struct FIRMWARE_INFO | ||
169 | { | ||
170 | uint32_t signature; /*0, 00-03*/ | ||
171 | uint32_t request_len; /*1, 04-07*/ | ||
172 | uint32_t numbers_queue; /*2, 08-11*/ | ||
173 | uint32_t sdram_size; /*3, 12-15*/ | ||
174 | uint32_t ide_channels; /*4, 16-19*/ | ||
175 | char vendor[40]; /*5, 20-59*/ | ||
176 | char model[8]; /*15, 60-67*/ | ||
177 | char firmware_ver[16]; /*17, 68-83*/ | ||
178 | char device_map[16]; /*21, 84-99*/ | ||
179 | }; | ||
180 | /* signature of set and get firmware config */ | ||
181 | #define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 | ||
182 | #define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 | ||
183 | /* message code of inbound message register */ | ||
184 | #define ARCMSR_INBOUND_MESG0_NOP 0x00000000 | ||
185 | #define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 | ||
186 | #define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002 | ||
187 | #define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003 | ||
188 | #define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004 | ||
189 | #define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005 | ||
190 | #define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006 | ||
191 | #define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007 | ||
192 | #define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008 | ||
193 | /* doorbell interrupt generator */ | ||
194 | #define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001 | ||
195 | #define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002 | ||
196 | #define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001 | ||
197 | #define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002 | ||
198 | /* ccb areca cdb flag */ | ||
199 | #define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000 | ||
200 | #define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000 | ||
201 | #define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000 | ||
202 | #define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 | ||
203 | /* outbound firmware ok */ | ||
204 | #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 | ||
205 | /* | ||
206 | ******************************************************************************* | ||
207 | ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) | ||
208 | ******************************************************************************* | ||
209 | */ | ||
210 | struct ARCMSR_CDB | ||
211 | { | ||
212 | uint8_t Bus; | ||
213 | uint8_t TargetID; | ||
214 | uint8_t LUN; | ||
215 | uint8_t Function; | ||
216 | |||
217 | uint8_t CdbLength; | ||
218 | uint8_t sgcount; | ||
219 | uint8_t Flags; | ||
220 | #define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01 | ||
221 | #define ARCMSR_CDB_FLAG_BIOS 0x02 | ||
222 | #define ARCMSR_CDB_FLAG_WRITE 0x04 | ||
223 | #define ARCMSR_CDB_FLAG_SIMPLEQ 0x00 | ||
224 | #define ARCMSR_CDB_FLAG_HEADQ 0x08 | ||
225 | #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 | ||
226 | uint8_t Reserved1; | ||
227 | |||
228 | uint32_t Context; | ||
229 | uint32_t DataLength; | ||
230 | |||
231 | uint8_t Cdb[16]; | ||
232 | |||
233 | uint8_t DeviceStatus; | ||
234 | #define ARCMSR_DEV_CHECK_CONDITION 0x02 | ||
235 | #define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 | ||
236 | #define ARCMSR_DEV_ABORTED 0xF1 | ||
237 | #define ARCMSR_DEV_INIT_FAIL 0xF2 | ||
238 | uint8_t SenseData[15]; | ||
239 | |||
240 | union | ||
241 | { | ||
242 | struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; | ||
243 | struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES]; | ||
244 | } u; | ||
245 | }; | ||
246 | /* | ||
247 | ******************************************************************************* | ||
248 | ** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331) | ||
249 | ******************************************************************************* | ||
250 | */ | ||
251 | struct MessageUnit | ||
252 | { | ||
253 | uint32_t resrved0[4]; /*0000 000F*/ | ||
254 | uint32_t inbound_msgaddr0; /*0010 0013*/ | ||
255 | uint32_t inbound_msgaddr1; /*0014 0017*/ | ||
256 | uint32_t outbound_msgaddr0; /*0018 001B*/ | ||
257 | uint32_t outbound_msgaddr1; /*001C 001F*/ | ||
258 | uint32_t inbound_doorbell; /*0020 0023*/ | ||
259 | uint32_t inbound_intstatus; /*0024 0027*/ | ||
260 | uint32_t inbound_intmask; /*0028 002B*/ | ||
261 | uint32_t outbound_doorbell; /*002C 002F*/ | ||
262 | uint32_t outbound_intstatus; /*0030 0033*/ | ||
263 | uint32_t outbound_intmask; /*0034 0037*/ | ||
264 | uint32_t reserved1[2]; /*0038 003F*/ | ||
265 | uint32_t inbound_queueport; /*0040 0043*/ | ||
266 | uint32_t outbound_queueport; /*0044 0047*/ | ||
267 | uint32_t reserved2[2]; /*0048 004F*/ | ||
268 | uint32_t reserved3[492]; /*0050 07FF 492*/ | ||
269 | uint32_t reserved4[128]; /*0800 09FF 128*/ | ||
270 | uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/ | ||
271 | uint32_t message_wbuffer[32]; /*0E00 0E7F 32*/ | ||
272 | uint32_t reserved5[32]; /*0E80 0EFF 32*/ | ||
273 | uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/ | ||
274 | uint32_t reserved6[32]; /*0F80 0FFF 32*/ | ||
275 | }; | ||
276 | /* | ||
277 | ******************************************************************************* | ||
278 | ** Adapter Control Block | ||
279 | ******************************************************************************* | ||
280 | */ | ||
281 | struct AdapterControlBlock | ||
282 | { | ||
283 | struct pci_dev * pdev; | ||
284 | struct Scsi_Host * host; | ||
285 | unsigned long vir2phy_offset; | ||
286 | /* Offset is used in making arc cdb physical to virtual calculations */ | ||
287 | uint32_t outbound_int_enable; | ||
288 | |||
289 | struct MessageUnit __iomem * pmu; | ||
290 | /* message unit ATU inbound base address0 */ | ||
291 | |||
292 | uint32_t acb_flags; | ||
293 | #define ACB_F_SCSISTOPADAPTER 0x0001 | ||
294 | #define ACB_F_MSG_STOP_BGRB 0x0002 | ||
295 | /* stop RAID background rebuild */ | ||
296 | #define ACB_F_MSG_START_BGRB 0x0004 | ||
297 | /* stop RAID background rebuild */ | ||
298 | #define ACB_F_IOPDATA_OVERFLOW 0x0008 | ||
299 | /* iop message data rqbuffer overflow */ | ||
300 | #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 | ||
301 | /* message clear wqbuffer */ | ||
302 | #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 | ||
303 | /* message clear rqbuffer */ | ||
304 | #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 | ||
305 | #define ACB_F_BUS_RESET 0x0080 | ||
306 | #define ACB_F_IOP_INITED 0x0100 | ||
307 | /* iop init */ | ||
308 | |||
309 | struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; | ||
310 | /* used for memory free */ | ||
311 | struct list_head ccb_free_list; | ||
312 | /* head of free ccb list */ | ||
313 | atomic_t ccboutstandingcount; | ||
314 | |||
315 | void * dma_coherent; | ||
316 | /* dma_coherent used for memory free */ | ||
317 | dma_addr_t dma_coherent_handle; | ||
318 | /* dma_coherent_handle used for memory free */ | ||
319 | |||
320 | uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; | ||
321 | /* data collection buffer for read from 80331 */ | ||
322 | int32_t rqbuf_firstindex; | ||
323 | /* first of read buffer */ | ||
324 | int32_t rqbuf_lastindex; | ||
325 | /* last of read buffer */ | ||
326 | uint8_t wqbuffer[ARCMSR_MAX_QBUFFER]; | ||
327 | /* data collection buffer for write to 80331 */ | ||
328 | int32_t wqbuf_firstindex; | ||
329 | /* first of write buffer */ | ||
330 | int32_t wqbuf_lastindex; | ||
331 | /* last of write buffer */ | ||
332 | uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN]; | ||
333 | /* id0 ..... id15, lun0...lun7 */ | ||
334 | #define ARECA_RAID_GONE 0x55 | ||
335 | #define ARECA_RAID_GOOD 0xaa | ||
336 | uint32_t num_resets; | ||
337 | uint32_t num_aborts; | ||
338 | uint32_t firm_request_len; | ||
339 | uint32_t firm_numbers_queue; | ||
340 | uint32_t firm_sdram_size; | ||
341 | uint32_t firm_hd_channels; | ||
342 | char firm_model[12]; | ||
343 | char firm_version[20]; | ||
344 | };/* HW_DEVICE_EXTENSION */ | ||
345 | /* | ||
346 | ******************************************************************************* | ||
347 | ** Command Control Block | ||
348 | ** this CCB length must be 32 bytes boundary | ||
349 | ******************************************************************************* | ||
350 | */ | ||
351 | struct CommandControlBlock | ||
352 | { | ||
353 | struct ARCMSR_CDB arcmsr_cdb; | ||
354 | /* | ||
355 | ** 0-503 (size of CDB=504): | ||
356 | ** arcmsr messenger scsi command descriptor size 504 bytes | ||
357 | */ | ||
358 | uint32_t cdb_shifted_phyaddr; | ||
359 | /* 504-507 */ | ||
360 | uint32_t reserved1; | ||
361 | /* 508-511 */ | ||
362 | #if BITS_PER_LONG == 64 | ||
363 | /* ======================512+64 bytes======================== */ | ||
364 | struct list_head list; | ||
365 | /* 512-527 16 bytes next/prev ptrs for ccb lists */ | ||
366 | struct scsi_cmnd * pcmd; | ||
367 | /* 528-535 8 bytes pointer of linux scsi command */ | ||
368 | struct AdapterControlBlock * acb; | ||
369 | /* 536-543 8 bytes pointer of acb */ | ||
370 | |||
371 | uint16_t ccb_flags; | ||
372 | /* 544-545 */ | ||
373 | #define CCB_FLAG_READ 0x0000 | ||
374 | #define CCB_FLAG_WRITE 0x0001 | ||
375 | #define CCB_FLAG_ERROR 0x0002 | ||
376 | #define CCB_FLAG_FLUSHCACHE 0x0004 | ||
377 | #define CCB_FLAG_MASTER_ABORTED 0x0008 | ||
378 | uint16_t startdone; | ||
379 | /* 546-547 */ | ||
380 | #define ARCMSR_CCB_DONE 0x0000 | ||
381 | #define ARCMSR_CCB_START 0x55AA | ||
382 | #define ARCMSR_CCB_ABORTED 0xAA55 | ||
383 | #define ARCMSR_CCB_ILLEGAL 0xFFFF | ||
384 | uint32_t reserved2[7]; | ||
385 | /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */ | ||
386 | #else | ||
387 | /* ======================512+32 bytes======================== */ | ||
388 | struct list_head list; | ||
389 | /* 512-519 8 bytes next/prev ptrs for ccb lists */ | ||
390 | struct scsi_cmnd * pcmd; | ||
391 | /* 520-523 4 bytes pointer of linux scsi command */ | ||
392 | struct AdapterControlBlock * acb; | ||
393 | /* 524-527 4 bytes pointer of acb */ | ||
394 | |||
395 | uint16_t ccb_flags; | ||
396 | /* 528-529 */ | ||
397 | #define CCB_FLAG_READ 0x0000 | ||
398 | #define CCB_FLAG_WRITE 0x0001 | ||
399 | #define CCB_FLAG_ERROR 0x0002 | ||
400 | #define CCB_FLAG_FLUSHCACHE 0x0004 | ||
401 | #define CCB_FLAG_MASTER_ABORTED 0x0008 | ||
402 | uint16_t startdone; | ||
403 | /* 530-531 */ | ||
404 | #define ARCMSR_CCB_DONE 0x0000 | ||
405 | #define ARCMSR_CCB_START 0x55AA | ||
406 | #define ARCMSR_CCB_ABORTED 0xAA55 | ||
407 | #define ARCMSR_CCB_ILLEGAL 0xFFFF | ||
408 | uint32_t reserved2[3]; | ||
409 | /* 532-535 536-539 540-543 */ | ||
410 | #endif | ||
411 | /* ========================================================== */ | ||
412 | }; | ||
413 | /* | ||
414 | ******************************************************************************* | ||
415 | ** ARECA SCSI sense data | ||
416 | ******************************************************************************* | ||
417 | */ | ||
418 | struct SENSE_DATA | ||
419 | { | ||
420 | uint8_t ErrorCode:7; | ||
421 | #define SCSI_SENSE_CURRENT_ERRORS 0x70 | ||
422 | #define SCSI_SENSE_DEFERRED_ERRORS 0x71 | ||
423 | uint8_t Valid:1; | ||
424 | uint8_t SegmentNumber; | ||
425 | uint8_t SenseKey:4; | ||
426 | uint8_t Reserved:1; | ||
427 | uint8_t IncorrectLength:1; | ||
428 | uint8_t EndOfMedia:1; | ||
429 | uint8_t FileMark:1; | ||
430 | uint8_t Information[4]; | ||
431 | uint8_t AdditionalSenseLength; | ||
432 | uint8_t CommandSpecificInformation[4]; | ||
433 | uint8_t AdditionalSenseCode; | ||
434 | uint8_t AdditionalSenseCodeQualifier; | ||
435 | uint8_t FieldReplaceableUnitCode; | ||
436 | uint8_t SenseKeySpecific[3]; | ||
437 | }; | ||
438 | /* | ||
439 | ******************************************************************************* | ||
440 | ** Outbound Interrupt Status Register - OISR | ||
441 | ******************************************************************************* | ||
442 | */ | ||
443 | #define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30 | ||
444 | #define ARCMSR_MU_OUTBOUND_PCI_INT 0x10 | ||
445 | #define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08 | ||
446 | #define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04 | ||
447 | #define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02 | ||
448 | #define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01 | ||
449 | #define ARCMSR_MU_OUTBOUND_HANDLE_INT \ | ||
450 | (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \ | ||
451 | |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \ | ||
452 | |ARCMSR_MU_OUTBOUND_DOORBELL_INT \ | ||
453 | |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \ | ||
454 | |ARCMSR_MU_OUTBOUND_PCI_INT) | ||
455 | /* | ||
456 | ******************************************************************************* | ||
457 | ** Outbound Interrupt Mask Register - OIMR | ||
458 | ******************************************************************************* | ||
459 | */ | ||
460 | #define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34 | ||
461 | #define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10 | ||
462 | #define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08 | ||
463 | #define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04 | ||
464 | #define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02 | ||
465 | #define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 | ||
466 | #define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F | ||
467 | |||
468 | extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb); | ||
469 | extern struct class_device_attribute *arcmsr_host_attrs[]; | ||
470 | extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb); | ||
471 | void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb); | ||
472 | |||
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c new file mode 100644 index 000000000000..0459f4194d7c --- /dev/null +++ b/drivers/scsi/arcmsr/arcmsr_attr.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | ******************************************************************************* | ||
3 | ** O.S : Linux | ||
4 | ** FILE NAME : arcmsr_attr.c | ||
5 | ** BY : Erich Chen | ||
6 | ** Description: attributes exported to sysfs and device host | ||
7 | ******************************************************************************* | ||
8 | ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved | ||
9 | ** | ||
10 | ** Web site: www.areca.com.tw | ||
11 | ** E-mail: erich@areca.com.tw | ||
12 | ** | ||
13 | ** This program is free software; you can redistribute it and/or modify | ||
14 | ** it under the terms of the GNU General Public License version 2 as | ||
15 | ** published by the Free Software Foundation. | ||
16 | ** This program is distributed in the hope that it will be useful, | ||
17 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | ** GNU General Public License for more details. | ||
20 | ******************************************************************************* | ||
21 | ** Redistribution and use in source and binary forms, with or without | ||
22 | ** modification, are permitted provided that the following conditions | ||
23 | ** are met: | ||
24 | ** 1. Redistributions of source code must retain the above copyright | ||
25 | ** notice, this list of conditions and the following disclaimer. | ||
26 | ** 2. Redistributions in binary form must reproduce the above copyright | ||
27 | ** notice, this list of conditions and the following disclaimer in the | ||
28 | ** documentation and/or other materials provided with the distribution. | ||
29 | ** 3. The name of the author may not be used to endorse or promote products | ||
30 | ** derived from this software without specific prior written permission. | ||
31 | ** | ||
32 | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
33 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
34 | ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
35 | ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
36 | ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT | ||
37 | ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
38 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY | ||
39 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
40 | ** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF | ||
41 | ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
42 | ******************************************************************************* | ||
43 | ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr | ||
44 | ** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt | ||
45 | ******************************************************************************* | ||
46 | */ | ||
47 | #include <linux/module.h> | ||
48 | #include <linux/kernel.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/errno.h> | ||
51 | #include <linux/delay.h> | ||
52 | #include <linux/pci.h> | ||
53 | |||
54 | #include <scsi/scsi_cmnd.h> | ||
55 | #include <scsi/scsi_device.h> | ||
56 | #include <scsi/scsi_host.h> | ||
57 | #include <scsi/scsi_transport.h> | ||
58 | #include "arcmsr.h" | ||
59 | |||
60 | struct class_device_attribute *arcmsr_host_attrs[]; | ||
61 | |||
62 | static ssize_t | ||
63 | arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off, | ||
64 | size_t count) | ||
65 | { | ||
66 | struct class_device *cdev = container_of(kobj,struct class_device,kobj); | ||
67 | struct Scsi_Host *host = class_to_shost(cdev); | ||
68 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
69 | struct MessageUnit __iomem *reg = acb->pmu; | ||
70 | uint8_t *pQbuffer,*ptmpQbuffer; | ||
71 | int32_t allxfer_len = 0; | ||
72 | |||
73 | if (!capable(CAP_SYS_ADMIN)) | ||
74 | return -EACCES; | ||
75 | |||
76 | /* do message unit read. */ | ||
77 | ptmpQbuffer = (uint8_t *)buf; | ||
78 | while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) | ||
79 | && (allxfer_len < 1031)) { | ||
80 | pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; | ||
81 | memcpy(ptmpQbuffer, pQbuffer, 1); | ||
82 | acb->rqbuf_firstindex++; | ||
83 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | ||
84 | ptmpQbuffer++; | ||
85 | allxfer_len++; | ||
86 | } | ||
87 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
88 | struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) | ||
89 | ®->message_rbuffer; | ||
90 | uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; | ||
91 | int32_t iop_len; | ||
92 | |||
93 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
94 | iop_len = readl(&prbuffer->data_len); | ||
95 | while (iop_len > 0) { | ||
96 | acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); | ||
97 | acb->rqbuf_lastindex++; | ||
98 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
99 | iop_data++; | ||
100 | iop_len--; | ||
101 | } | ||
102 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, | ||
103 | ®->inbound_doorbell); | ||
104 | } | ||
105 | return (allxfer_len); | ||
106 | } | ||
107 | |||
108 | static ssize_t | ||
109 | arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off, | ||
110 | size_t count) | ||
111 | { | ||
112 | struct class_device *cdev = container_of(kobj,struct class_device,kobj); | ||
113 | struct Scsi_Host *host = class_to_shost(cdev); | ||
114 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
115 | int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | ||
116 | uint8_t *pQbuffer, *ptmpuserbuffer; | ||
117 | |||
118 | if (!capable(CAP_SYS_ADMIN)) | ||
119 | return -EACCES; | ||
120 | if (count > 1032) | ||
121 | return -EINVAL; | ||
122 | /* do message unit write. */ | ||
123 | ptmpuserbuffer = (uint8_t *)buf; | ||
124 | user_len = (int32_t)count; | ||
125 | wqbuf_lastindex = acb->wqbuf_lastindex; | ||
126 | wqbuf_firstindex = acb->wqbuf_firstindex; | ||
127 | if (wqbuf_lastindex != wqbuf_firstindex) { | ||
128 | arcmsr_post_Qbuffer(acb); | ||
129 | return 0; /*need retry*/ | ||
130 | } else { | ||
131 | my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) | ||
132 | &(ARCMSR_MAX_QBUFFER - 1); | ||
133 | if (my_empty_len >= user_len) { | ||
134 | while (user_len > 0) { | ||
135 | pQbuffer = | ||
136 | &acb->wqbuffer[acb->wqbuf_lastindex]; | ||
137 | memcpy(pQbuffer, ptmpuserbuffer, 1); | ||
138 | acb->wqbuf_lastindex++; | ||
139 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
140 | ptmpuserbuffer++; | ||
141 | user_len--; | ||
142 | } | ||
143 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | ||
144 | acb->acb_flags &= | ||
145 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; | ||
146 | arcmsr_post_Qbuffer(acb); | ||
147 | } | ||
148 | return count; | ||
149 | } else { | ||
150 | return 0; /*need retry*/ | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static ssize_t | ||
156 | arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off, | ||
157 | size_t count) | ||
158 | { | ||
159 | struct class_device *cdev = container_of(kobj,struct class_device,kobj); | ||
160 | struct Scsi_Host *host = class_to_shost(cdev); | ||
161 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
162 | struct MessageUnit __iomem *reg = acb->pmu; | ||
163 | uint8_t *pQbuffer; | ||
164 | |||
165 | if (!capable(CAP_SYS_ADMIN)) | ||
166 | return -EACCES; | ||
167 | |||
168 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
169 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
170 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK | ||
171 | , ®->inbound_doorbell); | ||
172 | } | ||
173 | acb->acb_flags |= | ||
174 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | ||
175 | | ACB_F_MESSAGE_RQBUFFER_CLEARED | ||
176 | | ACB_F_MESSAGE_WQBUFFER_READED); | ||
177 | acb->rqbuf_firstindex = 0; | ||
178 | acb->rqbuf_lastindex = 0; | ||
179 | acb->wqbuf_firstindex = 0; | ||
180 | acb->wqbuf_lastindex = 0; | ||
181 | pQbuffer = acb->rqbuffer; | ||
182 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | ||
183 | pQbuffer = acb->wqbuffer; | ||
184 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | static struct bin_attribute arcmsr_sysfs_message_read_attr = { | ||
189 | .attr = { | ||
190 | .name = "mu_read", | ||
191 | .mode = S_IRUSR , | ||
192 | .owner = THIS_MODULE, | ||
193 | }, | ||
194 | .size = 1032, | ||
195 | .read = arcmsr_sysfs_iop_message_read, | ||
196 | }; | ||
197 | |||
198 | static struct bin_attribute arcmsr_sysfs_message_write_attr = { | ||
199 | .attr = { | ||
200 | .name = "mu_write", | ||
201 | .mode = S_IWUSR, | ||
202 | .owner = THIS_MODULE, | ||
203 | }, | ||
204 | .size = 1032, | ||
205 | .write = arcmsr_sysfs_iop_message_write, | ||
206 | }; | ||
207 | |||
208 | static struct bin_attribute arcmsr_sysfs_message_clear_attr = { | ||
209 | .attr = { | ||
210 | .name = "mu_clear", | ||
211 | .mode = S_IWUSR, | ||
212 | .owner = THIS_MODULE, | ||
213 | }, | ||
214 | .size = 1, | ||
215 | .write = arcmsr_sysfs_iop_message_clear, | ||
216 | }; | ||
217 | |||
218 | int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) | ||
219 | { | ||
220 | struct Scsi_Host *host = acb->host; | ||
221 | int error; | ||
222 | |||
223 | error = sysfs_create_bin_file(&host->shost_classdev.kobj, | ||
224 | &arcmsr_sysfs_message_read_attr); | ||
225 | if (error) { | ||
226 | printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n"); | ||
227 | goto error_bin_file_message_read; | ||
228 | } | ||
229 | error = sysfs_create_bin_file(&host->shost_classdev.kobj, | ||
230 | &arcmsr_sysfs_message_write_attr); | ||
231 | if (error) { | ||
232 | printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n"); | ||
233 | goto error_bin_file_message_write; | ||
234 | } | ||
235 | error = sysfs_create_bin_file(&host->shost_classdev.kobj, | ||
236 | &arcmsr_sysfs_message_clear_attr); | ||
237 | if (error) { | ||
238 | printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n"); | ||
239 | goto error_bin_file_message_clear; | ||
240 | } | ||
241 | return 0; | ||
242 | error_bin_file_message_clear: | ||
243 | error = sysfs_remove_bin_file(&host->shost_classdev.kobj, | ||
244 | &arcmsr_sysfs_message_write_attr); | ||
245 | if (error) | ||
246 | printk(KERN_ERR "arcmsr: sysfs_remove_bin_file mu_write failed\n"); | ||
247 | error_bin_file_message_write: | ||
248 | error = sysfs_remove_bin_file(&host->shost_classdev.kobj, | ||
249 | &arcmsr_sysfs_message_read_attr); | ||
250 | if (error) | ||
251 | printk(KERN_ERR "arcmsr: sysfs_remove_bin_file mu_read failed\n"); | ||
252 | error_bin_file_message_read: | ||
253 | return error; | ||
254 | } | ||
255 | |||
256 | void | ||
257 | arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) { | ||
258 | struct Scsi_Host *host = acb->host; | ||
259 | int error; | ||
260 | |||
261 | error = sysfs_remove_bin_file(&host->shost_classdev.kobj, | ||
262 | &arcmsr_sysfs_message_clear_attr); | ||
263 | if (error) | ||
264 | printk(KERN_ERR "arcmsr: free sysfs mu_clear failed\n"); | ||
265 | error = sysfs_remove_bin_file(&host->shost_classdev.kobj, | ||
266 | &arcmsr_sysfs_message_write_attr); | ||
267 | if (error) | ||
268 | printk(KERN_ERR "arcmsr: free sysfs mu_write failed\n"); | ||
269 | error = sysfs_remove_bin_file(&host->shost_classdev.kobj, | ||
270 | &arcmsr_sysfs_message_read_attr); | ||
271 | if (error) | ||
272 | printk(KERN_ERR "arcmsr: free sysfss mu_read failed\n"); | ||
273 | } | ||
274 | |||
275 | |||
276 | static ssize_t | ||
277 | arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) { | ||
278 | return snprintf(buf, PAGE_SIZE, | ||
279 | "ARCMSR: %s\n", | ||
280 | ARCMSR_DRIVER_VERSION); | ||
281 | } | ||
282 | |||
283 | static ssize_t | ||
284 | arcmsr_attr_host_driver_posted_cmd(struct class_device *cdev, char *buf) { | ||
285 | struct Scsi_Host *host = class_to_shost(cdev); | ||
286 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
287 | return snprintf(buf, PAGE_SIZE, | ||
288 | "Current commands posted: %4d\n", | ||
289 | atomic_read(&acb->ccboutstandingcount)); | ||
290 | } | ||
291 | |||
292 | static ssize_t | ||
293 | arcmsr_attr_host_driver_reset(struct class_device *cdev, char *buf) { | ||
294 | struct Scsi_Host *host = class_to_shost(cdev); | ||
295 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
296 | return snprintf(buf, PAGE_SIZE, | ||
297 | "SCSI Host Resets: %4d\n", | ||
298 | acb->num_resets); | ||
299 | } | ||
300 | |||
301 | static ssize_t | ||
302 | arcmsr_attr_host_driver_abort(struct class_device *cdev, char *buf) { | ||
303 | struct Scsi_Host *host = class_to_shost(cdev); | ||
304 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
305 | return snprintf(buf, PAGE_SIZE, | ||
306 | "SCSI Aborts/Timeouts: %4d\n", | ||
307 | acb->num_aborts); | ||
308 | } | ||
309 | |||
310 | static ssize_t | ||
311 | arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) { | ||
312 | struct Scsi_Host *host = class_to_shost(cdev); | ||
313 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
314 | return snprintf(buf, PAGE_SIZE, | ||
315 | "Adapter Model: %s\n", | ||
316 | acb->firm_model); | ||
317 | } | ||
318 | |||
319 | static ssize_t | ||
320 | arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) { | ||
321 | struct Scsi_Host *host = class_to_shost(cdev); | ||
322 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
323 | |||
324 | return snprintf(buf, PAGE_SIZE, | ||
325 | "Firmware Version: %s\n", | ||
326 | acb->firm_version); | ||
327 | } | ||
328 | |||
329 | static ssize_t | ||
330 | arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) { | ||
331 | struct Scsi_Host *host = class_to_shost(cdev); | ||
332 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
333 | |||
334 | return snprintf(buf, PAGE_SIZE, | ||
335 | "Reguest Lenth: %4d\n", | ||
336 | acb->firm_request_len); | ||
337 | } | ||
338 | |||
339 | static ssize_t | ||
340 | arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) { | ||
341 | struct Scsi_Host *host = class_to_shost(cdev); | ||
342 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
343 | |||
344 | return snprintf(buf, PAGE_SIZE, | ||
345 | "Numbers of Queue: %4d\n", | ||
346 | acb->firm_numbers_queue); | ||
347 | } | ||
348 | |||
349 | static ssize_t | ||
350 | arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) { | ||
351 | struct Scsi_Host *host = class_to_shost(cdev); | ||
352 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
353 | |||
354 | return snprintf(buf, PAGE_SIZE, | ||
355 | "SDRAM Size: %4d\n", | ||
356 | acb->firm_sdram_size); | ||
357 | } | ||
358 | |||
359 | static ssize_t | ||
360 | arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) { | ||
361 | struct Scsi_Host *host = class_to_shost(cdev); | ||
362 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
363 | |||
364 | return snprintf(buf, PAGE_SIZE, | ||
365 | "Hard Disk Channels: %4d\n", | ||
366 | acb->firm_hd_channels); | ||
367 | } | ||
368 | |||
369 | static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL); | ||
370 | static CLASS_DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL); | ||
371 | static CLASS_DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL); | ||
372 | static CLASS_DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL); | ||
373 | static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL); | ||
374 | static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL); | ||
375 | static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL); | ||
376 | static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL); | ||
377 | static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL); | ||
378 | static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL); | ||
379 | |||
380 | struct class_device_attribute *arcmsr_host_attrs[] = { | ||
381 | &class_device_attr_host_driver_version, | ||
382 | &class_device_attr_host_driver_posted_cmd, | ||
383 | &class_device_attr_host_driver_reset, | ||
384 | &class_device_attr_host_driver_abort, | ||
385 | &class_device_attr_host_fw_model, | ||
386 | &class_device_attr_host_fw_version, | ||
387 | &class_device_attr_host_fw_request_len, | ||
388 | &class_device_attr_host_fw_numbers_queue, | ||
389 | &class_device_attr_host_fw_sdram_size, | ||
390 | &class_device_attr_host_fw_hd_channels, | ||
391 | NULL, | ||
392 | }; | ||
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c new file mode 100644 index 000000000000..475f978ff8f0 --- /dev/null +++ b/drivers/scsi/arcmsr/arcmsr_hba.c | |||
@@ -0,0 +1,1496 @@ | |||
1 | /* | ||
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 | ||
12 | ** E-mail: erich@areca.com.tw | ||
13 | ** | ||
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> | ||
60 | #include <asm/dma.h> | ||
61 | #include <asm/io.h> | ||
62 | #include <asm/system.h> | ||
63 | #include <asm/uaccess.h> | ||
64 | #include <scsi/scsi_host.h> | ||
65 | #include <scsi/scsi.h> | ||
66 | #include <scsi/scsi_cmnd.h> | ||
67 | #include <scsi/scsi_tcq.h> | ||
68 | #include <scsi/scsi_device.h> | ||
69 | #include <scsi/scsi_transport.h> | ||
70 | #include <scsi/scsicam.h> | ||
71 | #include "arcmsr.h" | ||
72 | |||
73 | MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>"); | ||
74 | MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter"); | ||
75 | MODULE_LICENSE("Dual BSD/GPL"); | ||
76 | MODULE_VERSION(ARCMSR_DRIVER_VERSION); | ||
77 | |||
78 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); | ||
79 | static int arcmsr_abort(struct scsi_cmnd *); | ||
80 | static int arcmsr_bus_reset(struct scsi_cmnd *); | ||
81 | static int arcmsr_bios_param(struct scsi_device *sdev, | ||
82 | struct block_device *bdev, sector_t capacity, int *info); | ||
83 | static int arcmsr_queue_command(struct scsi_cmnd * cmd, | ||
84 | void (*done) (struct scsi_cmnd *)); | ||
85 | static int arcmsr_probe(struct pci_dev *pdev, | ||
86 | const struct pci_device_id *id); | ||
87 | static void arcmsr_remove(struct pci_dev *pdev); | ||
88 | static void arcmsr_shutdown(struct pci_dev *pdev); | ||
89 | static void arcmsr_iop_init(struct AdapterControlBlock *acb); | ||
90 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); | ||
91 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); | ||
92 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); | ||
93 | static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb); | ||
94 | static const char *arcmsr_info(struct Scsi_Host *); | ||
95 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); | ||
96 | |||
97 | static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) | ||
98 | { | ||
99 | if (queue_depth > ARCMSR_MAX_CMD_PERLUN) | ||
100 | queue_depth = ARCMSR_MAX_CMD_PERLUN; | ||
101 | scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); | ||
102 | return queue_depth; | ||
103 | } | ||
104 | |||
105 | static struct scsi_host_template arcmsr_scsi_host_template = { | ||
106 | .module = THIS_MODULE, | ||
107 | .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION, | ||
108 | .info = arcmsr_info, | ||
109 | .queuecommand = arcmsr_queue_command, | ||
110 | .eh_abort_handler = arcmsr_abort, | ||
111 | .eh_bus_reset_handler = arcmsr_bus_reset, | ||
112 | .bios_param = arcmsr_bios_param, | ||
113 | .change_queue_depth = arcmsr_adjust_disk_queue_depth, | ||
114 | .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, | ||
115 | .this_id = ARCMSR_SCSI_INITIATOR_ID, | ||
116 | .sg_tablesize = ARCMSR_MAX_SG_ENTRIES, | ||
117 | .max_sectors = ARCMSR_MAX_XFER_SECTORS, | ||
118 | .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, | ||
119 | .use_clustering = ENABLE_CLUSTERING, | ||
120 | .shost_attrs = arcmsr_host_attrs, | ||
121 | }; | ||
122 | |||
123 | static struct pci_device_id arcmsr_device_id_table[] = { | ||
124 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, | ||
125 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, | ||
126 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, | ||
127 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, | ||
128 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, | ||
129 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, | ||
130 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, | ||
131 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, | ||
132 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)}, | ||
133 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)}, | ||
134 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)}, | ||
135 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)}, | ||
136 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, | ||
137 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, | ||
138 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, | ||
139 | {0, 0}, /* Terminating entry */ | ||
140 | }; | ||
141 | MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); | ||
142 | static struct pci_driver arcmsr_pci_driver = { | ||
143 | .name = "arcmsr", | ||
144 | .id_table = arcmsr_device_id_table, | ||
145 | .probe = arcmsr_probe, | ||
146 | .remove = arcmsr_remove, | ||
147 | .shutdown = arcmsr_shutdown | ||
148 | }; | ||
149 | |||
150 | static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id, | ||
151 | struct pt_regs *regs) | ||
152 | { | ||
153 | irqreturn_t handle_state; | ||
154 | struct AdapterControlBlock *acb; | ||
155 | unsigned long flags; | ||
156 | |||
157 | acb = (struct AdapterControlBlock *)dev_id; | ||
158 | |||
159 | spin_lock_irqsave(acb->host->host_lock, flags); | ||
160 | handle_state = arcmsr_interrupt(acb); | ||
161 | spin_unlock_irqrestore(acb->host->host_lock, flags); | ||
162 | return handle_state; | ||
163 | } | ||
164 | |||
165 | static int arcmsr_bios_param(struct scsi_device *sdev, | ||
166 | struct block_device *bdev, sector_t capacity, int *geom) | ||
167 | { | ||
168 | int ret, heads, sectors, cylinders, total_capacity; | ||
169 | unsigned char *buffer;/* return copy of block device's partition table */ | ||
170 | |||
171 | buffer = scsi_bios_ptable(bdev); | ||
172 | if (buffer) { | ||
173 | ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]); | ||
174 | kfree(buffer); | ||
175 | if (ret != -1) | ||
176 | return ret; | ||
177 | } | ||
178 | total_capacity = capacity; | ||
179 | heads = 64; | ||
180 | sectors = 32; | ||
181 | cylinders = total_capacity / (heads * sectors); | ||
182 | if (cylinders > 1024) { | ||
183 | heads = 255; | ||
184 | sectors = 63; | ||
185 | cylinders = total_capacity / (heads * sectors); | ||
186 | } | ||
187 | geom[0] = heads; | ||
188 | geom[1] = sectors; | ||
189 | geom[2] = cylinders; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) | ||
194 | { | ||
195 | struct pci_dev *pdev = acb->pdev; | ||
196 | struct MessageUnit __iomem *reg = acb->pmu; | ||
197 | u32 ccb_phyaddr_hi32; | ||
198 | void *dma_coherent; | ||
199 | dma_addr_t dma_coherent_handle, dma_addr; | ||
200 | struct CommandControlBlock *ccb_tmp; | ||
201 | int i, j; | ||
202 | |||
203 | dma_coherent = dma_alloc_coherent(&pdev->dev, | ||
204 | ARCMSR_MAX_FREECCB_NUM * | ||
205 | sizeof (struct CommandControlBlock) + 0x20, | ||
206 | &dma_coherent_handle, GFP_KERNEL); | ||
207 | if (!dma_coherent) | ||
208 | return -ENOMEM; | ||
209 | |||
210 | acb->dma_coherent = dma_coherent; | ||
211 | acb->dma_coherent_handle = dma_coherent_handle; | ||
212 | |||
213 | if (((unsigned long)dma_coherent & 0x1F)) { | ||
214 | dma_coherent = dma_coherent + | ||
215 | (0x20 - ((unsigned long)dma_coherent & 0x1F)); | ||
216 | dma_coherent_handle = dma_coherent_handle + | ||
217 | (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); | ||
218 | } | ||
219 | |||
220 | dma_addr = dma_coherent_handle; | ||
221 | ccb_tmp = (struct CommandControlBlock *)dma_coherent; | ||
222 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | ||
223 | ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; | ||
224 | ccb_tmp->acb = acb; | ||
225 | acb->pccb_pool[i] = ccb_tmp; | ||
226 | list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); | ||
227 | dma_addr = dma_addr + sizeof (struct CommandControlBlock); | ||
228 | ccb_tmp++; | ||
229 | } | ||
230 | |||
231 | acb->vir2phy_offset = (unsigned long)ccb_tmp - | ||
232 | (unsigned long)dma_addr; | ||
233 | for (i = 0; i < ARCMSR_MAX_TARGETID; i++) | ||
234 | for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) | ||
235 | acb->devstate[i][j] = ARECA_RAID_GOOD; | ||
236 | |||
237 | /* | ||
238 | ** here we need to tell iop 331 our ccb_tmp.HighPart | ||
239 | ** if ccb_tmp.HighPart is not zero | ||
240 | */ | ||
241 | ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16); | ||
242 | if (ccb_phyaddr_hi32 != 0) { | ||
243 | writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->message_rwbuffer[0]); | ||
244 | writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); | ||
245 | writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); | ||
246 | if (arcmsr_wait_msgint_ready(acb)) | ||
247 | printk(KERN_NOTICE "arcmsr%d: " | ||
248 | "'set ccb high part physical address' timeout\n", | ||
249 | acb->host->host_no); | ||
250 | } | ||
251 | |||
252 | writel(readl(®->outbound_intmask) | | ||
253 | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, | ||
254 | ®->outbound_intmask); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int arcmsr_probe(struct pci_dev *pdev, | ||
259 | const struct pci_device_id *id) | ||
260 | { | ||
261 | struct Scsi_Host *host; | ||
262 | struct AdapterControlBlock *acb; | ||
263 | uint8_t bus, dev_fun; | ||
264 | int error; | ||
265 | |||
266 | error = pci_enable_device(pdev); | ||
267 | if (error) | ||
268 | goto out; | ||
269 | pci_set_master(pdev); | ||
270 | |||
271 | host = scsi_host_alloc(&arcmsr_scsi_host_template, | ||
272 | sizeof(struct AdapterControlBlock)); | ||
273 | if (!host) { | ||
274 | error = -ENOMEM; | ||
275 | goto out_disable_device; | ||
276 | } | ||
277 | acb = (struct AdapterControlBlock *)host->hostdata; | ||
278 | memset(acb, 0, sizeof (struct AdapterControlBlock)); | ||
279 | |||
280 | error = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | ||
281 | if (error) { | ||
282 | error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
283 | if (error) { | ||
284 | printk(KERN_WARNING | ||
285 | "scsi%d: No suitable DMA mask available\n", | ||
286 | host->host_no); | ||
287 | goto out_host_put; | ||
288 | } | ||
289 | } | ||
290 | bus = pdev->bus->number; | ||
291 | dev_fun = pdev->devfn; | ||
292 | acb->host = host; | ||
293 | acb->pdev = pdev; | ||
294 | host->max_sectors = ARCMSR_MAX_XFER_SECTORS; | ||
295 | host->max_lun = ARCMSR_MAX_TARGETLUN; | ||
296 | host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ | ||
297 | host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ | ||
298 | host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; | ||
299 | host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ | ||
300 | host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; | ||
301 | host->this_id = ARCMSR_SCSI_INITIATOR_ID; | ||
302 | host->unique_id = (bus << 8) | dev_fun; | ||
303 | host->irq = pdev->irq; | ||
304 | error = pci_request_regions(pdev, "arcmsr"); | ||
305 | if (error) | ||
306 | goto out_host_put; | ||
307 | |||
308 | acb->pmu = ioremap(pci_resource_start(pdev, 0), | ||
309 | pci_resource_len(pdev, 0)); | ||
310 | if (!acb->pmu) { | ||
311 | printk(KERN_NOTICE "arcmsr%d: memory" | ||
312 | " mapping region fail \n", acb->host->host_no); | ||
313 | goto out_release_regions; | ||
314 | } | ||
315 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | | ||
316 | ACB_F_MESSAGE_RQBUFFER_CLEARED | | ||
317 | ACB_F_MESSAGE_WQBUFFER_READED); | ||
318 | acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; | ||
319 | INIT_LIST_HEAD(&acb->ccb_free_list); | ||
320 | |||
321 | error = arcmsr_alloc_ccb_pool(acb); | ||
322 | if (error) | ||
323 | goto out_iounmap; | ||
324 | |||
325 | error = request_irq(pdev->irq, arcmsr_do_interrupt, | ||
326 | SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb); | ||
327 | if (error) | ||
328 | goto out_free_ccb_pool; | ||
329 | |||
330 | arcmsr_iop_init(acb); | ||
331 | pci_set_drvdata(pdev, host); | ||
332 | |||
333 | error = scsi_add_host(host, &pdev->dev); | ||
334 | if (error) | ||
335 | goto out_free_irq; | ||
336 | |||
337 | error = arcmsr_alloc_sysfs_attr(acb); | ||
338 | if (error) | ||
339 | goto out_free_sysfs; | ||
340 | |||
341 | scsi_scan_host(host); | ||
342 | return 0; | ||
343 | out_free_sysfs: | ||
344 | out_free_irq: | ||
345 | free_irq(pdev->irq, acb); | ||
346 | out_free_ccb_pool: | ||
347 | arcmsr_free_ccb_pool(acb); | ||
348 | out_iounmap: | ||
349 | iounmap(acb->pmu); | ||
350 | out_release_regions: | ||
351 | pci_release_regions(pdev); | ||
352 | out_host_put: | ||
353 | scsi_host_put(host); | ||
354 | out_disable_device: | ||
355 | pci_disable_device(pdev); | ||
356 | out: | ||
357 | return error; | ||
358 | } | ||
359 | |||
360 | static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) | ||
361 | { | ||
362 | struct MessageUnit __iomem *reg = acb->pmu; | ||
363 | |||
364 | writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); | ||
365 | if (arcmsr_wait_msgint_ready(acb)) | ||
366 | printk(KERN_NOTICE | ||
367 | "arcmsr%d: wait 'abort all outstanding command' timeout \n" | ||
368 | , acb->host->host_no); | ||
369 | } | ||
370 | |||
371 | static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) | ||
372 | { | ||
373 | struct AdapterControlBlock *acb = ccb->acb; | ||
374 | struct scsi_cmnd *pcmd = ccb->pcmd; | ||
375 | |||
376 | if (pcmd->use_sg != 0) { | ||
377 | struct scatterlist *sl; | ||
378 | |||
379 | sl = (struct scatterlist *)pcmd->request_buffer; | ||
380 | pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction); | ||
381 | } | ||
382 | else if (pcmd->request_bufflen != 0) | ||
383 | pci_unmap_single(acb->pdev, | ||
384 | pcmd->SCp.dma_handle, | ||
385 | pcmd->request_bufflen, pcmd->sc_data_direction); | ||
386 | } | ||
387 | |||
388 | static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag) | ||
389 | { | ||
390 | struct AdapterControlBlock *acb = ccb->acb; | ||
391 | struct scsi_cmnd *pcmd = ccb->pcmd; | ||
392 | |||
393 | arcmsr_pci_unmap_dma(ccb); | ||
394 | if (stand_flag == 1) | ||
395 | atomic_dec(&acb->ccboutstandingcount); | ||
396 | ccb->startdone = ARCMSR_CCB_DONE; | ||
397 | ccb->ccb_flags = 0; | ||
398 | list_add_tail(&ccb->list, &acb->ccb_free_list); | ||
399 | pcmd->scsi_done(pcmd); | ||
400 | } | ||
401 | |||
402 | static void arcmsr_remove(struct pci_dev *pdev) | ||
403 | { | ||
404 | struct Scsi_Host *host = pci_get_drvdata(pdev); | ||
405 | struct AdapterControlBlock *acb = | ||
406 | (struct AdapterControlBlock *) host->hostdata; | ||
407 | struct MessageUnit __iomem *reg = acb->pmu; | ||
408 | int poll_count = 0; | ||
409 | |||
410 | arcmsr_free_sysfs_attr(acb); | ||
411 | scsi_remove_host(host); | ||
412 | arcmsr_stop_adapter_bgrb(acb); | ||
413 | arcmsr_flush_adapter_cache(acb); | ||
414 | writel(readl(®->outbound_intmask) | | ||
415 | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, | ||
416 | ®->outbound_intmask); | ||
417 | acb->acb_flags |= ACB_F_SCSISTOPADAPTER; | ||
418 | acb->acb_flags &= ~ACB_F_IOP_INITED; | ||
419 | |||
420 | for (poll_count = 0; poll_count < 256; poll_count++) { | ||
421 | if (!atomic_read(&acb->ccboutstandingcount)) | ||
422 | break; | ||
423 | arcmsr_interrupt(acb); | ||
424 | msleep(25); | ||
425 | } | ||
426 | |||
427 | if (atomic_read(&acb->ccboutstandingcount)) { | ||
428 | int i; | ||
429 | |||
430 | arcmsr_abort_allcmd(acb); | ||
431 | for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) | ||
432 | readl(®->outbound_queueport); | ||
433 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | ||
434 | struct CommandControlBlock *ccb = acb->pccb_pool[i]; | ||
435 | if (ccb->startdone == ARCMSR_CCB_START) { | ||
436 | ccb->startdone = ARCMSR_CCB_ABORTED; | ||
437 | ccb->pcmd->result = DID_ABORT << 16; | ||
438 | arcmsr_ccb_complete(ccb, 1); | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | free_irq(pdev->irq, acb); | ||
444 | iounmap(acb->pmu); | ||
445 | arcmsr_free_ccb_pool(acb); | ||
446 | pci_release_regions(pdev); | ||
447 | |||
448 | scsi_host_put(host); | ||
449 | |||
450 | pci_disable_device(pdev); | ||
451 | pci_set_drvdata(pdev, NULL); | ||
452 | } | ||
453 | |||
454 | static void arcmsr_shutdown(struct pci_dev *pdev) | ||
455 | { | ||
456 | struct Scsi_Host *host = pci_get_drvdata(pdev); | ||
457 | struct AdapterControlBlock *acb = | ||
458 | (struct AdapterControlBlock *)host->hostdata; | ||
459 | |||
460 | arcmsr_stop_adapter_bgrb(acb); | ||
461 | arcmsr_flush_adapter_cache(acb); | ||
462 | } | ||
463 | |||
464 | static int arcmsr_module_init(void) | ||
465 | { | ||
466 | int error = 0; | ||
467 | |||
468 | error = pci_register_driver(&arcmsr_pci_driver); | ||
469 | return error; | ||
470 | } | ||
471 | |||
472 | static void arcmsr_module_exit(void) | ||
473 | { | ||
474 | pci_unregister_driver(&arcmsr_pci_driver); | ||
475 | } | ||
476 | module_init(arcmsr_module_init); | ||
477 | module_exit(arcmsr_module_exit); | ||
478 | |||
479 | static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) | ||
480 | { | ||
481 | struct MessageUnit __iomem *reg = acb->pmu; | ||
482 | u32 orig_mask = readl(®->outbound_intmask); | ||
483 | |||
484 | writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, | ||
485 | ®->outbound_intmask); | ||
486 | return orig_mask; | ||
487 | } | ||
488 | |||
489 | static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, | ||
490 | u32 orig_mask) | ||
491 | { | ||
492 | struct MessageUnit __iomem *reg = acb->pmu; | ||
493 | u32 mask; | ||
494 | |||
495 | mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | | ||
496 | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); | ||
497 | writel(mask, ®->outbound_intmask); | ||
498 | } | ||
499 | |||
500 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) | ||
501 | { | ||
502 | struct MessageUnit __iomem *reg=acb->pmu; | ||
503 | |||
504 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); | ||
505 | if (arcmsr_wait_msgint_ready(acb)) | ||
506 | printk(KERN_NOTICE | ||
507 | "arcmsr%d: wait 'flush adapter cache' timeout \n" | ||
508 | , acb->host->host_no); | ||
509 | } | ||
510 | |||
511 | static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) | ||
512 | { | ||
513 | struct scsi_cmnd *pcmd = ccb->pcmd; | ||
514 | struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; | ||
515 | |||
516 | pcmd->result = DID_OK << 16; | ||
517 | if (sensebuffer) { | ||
518 | int sense_data_length = | ||
519 | sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer) | ||
520 | ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer); | ||
521 | memset(sensebuffer, 0, sizeof (pcmd->sense_buffer)); | ||
522 | memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); | ||
523 | sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; | ||
524 | sensebuffer->Valid = 1; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb) | ||
529 | { | ||
530 | struct MessageUnit __iomem *reg = acb->pmu; | ||
531 | uint32_t Index; | ||
532 | uint8_t Retries = 0x00; | ||
533 | |||
534 | do { | ||
535 | for (Index = 0; Index < 100; Index++) { | ||
536 | if (readl(®->outbound_intstatus) | ||
537 | & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { | ||
538 | writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT | ||
539 | , ®->outbound_intstatus); | ||
540 | return 0x00; | ||
541 | } | ||
542 | msleep_interruptible(10); | ||
543 | }/*max 1 seconds*/ | ||
544 | } while (Retries++ < 20);/*max 20 sec*/ | ||
545 | return 0xff; | ||
546 | } | ||
547 | |||
548 | static void arcmsr_build_ccb(struct AdapterControlBlock *acb, | ||
549 | struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) | ||
550 | { | ||
551 | struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; | ||
552 | int8_t *psge = (int8_t *)&arcmsr_cdb->u; | ||
553 | uint32_t address_lo, address_hi; | ||
554 | int arccdbsize = 0x30; | ||
555 | |||
556 | ccb->pcmd = pcmd; | ||
557 | memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB)); | ||
558 | arcmsr_cdb->Bus = 0; | ||
559 | arcmsr_cdb->TargetID = pcmd->device->id; | ||
560 | arcmsr_cdb->LUN = pcmd->device->lun; | ||
561 | arcmsr_cdb->Function = 1; | ||
562 | arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len; | ||
563 | arcmsr_cdb->Context = (unsigned long)arcmsr_cdb; | ||
564 | memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); | ||
565 | if (pcmd->use_sg) { | ||
566 | int length, sgcount, i, cdb_sgcount = 0; | ||
567 | struct scatterlist *sl; | ||
568 | |||
569 | /* Get Scatter Gather List from scsiport. */ | ||
570 | sl = (struct scatterlist *) pcmd->request_buffer; | ||
571 | sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg, | ||
572 | pcmd->sc_data_direction); | ||
573 | /* map stor port SG list to our iop SG List. */ | ||
574 | for (i = 0; i < sgcount; i++) { | ||
575 | /* Get the physical address of the current data pointer */ | ||
576 | length = cpu_to_le32(sg_dma_len(sl)); | ||
577 | address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl))); | ||
578 | address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl))); | ||
579 | if (address_hi == 0) { | ||
580 | struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; | ||
581 | |||
582 | pdma_sg->address = address_lo; | ||
583 | pdma_sg->length = length; | ||
584 | psge += sizeof (struct SG32ENTRY); | ||
585 | arccdbsize += sizeof (struct SG32ENTRY); | ||
586 | } else { | ||
587 | struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; | ||
588 | |||
589 | pdma_sg->addresshigh = address_hi; | ||
590 | pdma_sg->address = address_lo; | ||
591 | pdma_sg->length = length|IS_SG64_ADDR; | ||
592 | psge += sizeof (struct SG64ENTRY); | ||
593 | arccdbsize += sizeof (struct SG64ENTRY); | ||
594 | } | ||
595 | sl++; | ||
596 | cdb_sgcount++; | ||
597 | } | ||
598 | arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount; | ||
599 | arcmsr_cdb->DataLength = pcmd->request_bufflen; | ||
600 | if ( arccdbsize > 256) | ||
601 | arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; | ||
602 | } else if (pcmd->request_bufflen) { | ||
603 | dma_addr_t dma_addr; | ||
604 | dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer, | ||
605 | pcmd->request_bufflen, pcmd->sc_data_direction); | ||
606 | pcmd->SCp.dma_handle = dma_addr; | ||
607 | address_lo = cpu_to_le32(dma_addr_lo32(dma_addr)); | ||
608 | address_hi = cpu_to_le32(dma_addr_hi32(dma_addr)); | ||
609 | if (address_hi == 0) { | ||
610 | struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; | ||
611 | pdma_sg->address = address_lo; | ||
612 | pdma_sg->length = pcmd->request_bufflen; | ||
613 | } else { | ||
614 | struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; | ||
615 | pdma_sg->addresshigh = address_hi; | ||
616 | pdma_sg->address = address_lo; | ||
617 | pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR; | ||
618 | } | ||
619 | arcmsr_cdb->sgcount = 1; | ||
620 | arcmsr_cdb->DataLength = pcmd->request_bufflen; | ||
621 | } | ||
622 | if (pcmd->sc_data_direction == DMA_TO_DEVICE ) { | ||
623 | arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; | ||
624 | ccb->ccb_flags |= CCB_FLAG_WRITE; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) | ||
629 | { | ||
630 | struct MessageUnit __iomem *reg = acb->pmu; | ||
631 | uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; | ||
632 | struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; | ||
633 | |||
634 | atomic_inc(&acb->ccboutstandingcount); | ||
635 | ccb->startdone = ARCMSR_CCB_START; | ||
636 | if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) | ||
637 | writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, | ||
638 | ®->inbound_queueport); | ||
639 | else | ||
640 | writel(cdb_shifted_phyaddr, ®->inbound_queueport); | ||
641 | } | ||
642 | |||
643 | void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb) | ||
644 | { | ||
645 | struct MessageUnit __iomem *reg = acb->pmu; | ||
646 | struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; | ||
647 | uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data; | ||
648 | int32_t allxfer_len = 0; | ||
649 | |||
650 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { | ||
651 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); | ||
652 | while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) | ||
653 | && (allxfer_len < 124)) { | ||
654 | writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); | ||
655 | acb->wqbuf_firstindex++; | ||
656 | acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | ||
657 | iop_data++; | ||
658 | allxfer_len++; | ||
659 | } | ||
660 | writel(allxfer_len, &pwbuffer->data_len); | ||
661 | writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK | ||
662 | , ®->inbound_doorbell); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) | ||
667 | { | ||
668 | struct MessageUnit __iomem *reg = acb->pmu; | ||
669 | |||
670 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | ||
671 | writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); | ||
672 | if (arcmsr_wait_msgint_ready(acb)) | ||
673 | printk(KERN_NOTICE | ||
674 | "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | ||
675 | , acb->host->host_no); | ||
676 | } | ||
677 | |||
678 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) | ||
679 | { | ||
680 | dma_free_coherent(&acb->pdev->dev, | ||
681 | ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, | ||
682 | acb->dma_coherent, | ||
683 | acb->dma_coherent_handle); | ||
684 | } | ||
685 | |||
686 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | ||
687 | { | ||
688 | struct MessageUnit __iomem *reg = acb->pmu; | ||
689 | struct CommandControlBlock *ccb; | ||
690 | uint32_t flag_ccb, outbound_intstatus, outbound_doorbell; | ||
691 | |||
692 | outbound_intstatus = readl(®->outbound_intstatus) | ||
693 | & acb->outbound_int_enable; | ||
694 | writel(outbound_intstatus, ®->outbound_intstatus); | ||
695 | if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { | ||
696 | outbound_doorbell = readl(®->outbound_doorbell); | ||
697 | writel(outbound_doorbell, ®->outbound_doorbell); | ||
698 | if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { | ||
699 | struct QBUFFER __iomem * prbuffer = | ||
700 | (struct QBUFFER __iomem *) ®->message_rbuffer; | ||
701 | uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; | ||
702 | int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; | ||
703 | |||
704 | rqbuf_lastindex = acb->rqbuf_lastindex; | ||
705 | rqbuf_firstindex = acb->rqbuf_firstindex; | ||
706 | iop_len = readl(&prbuffer->data_len); | ||
707 | my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) | ||
708 | &(ARCMSR_MAX_QBUFFER - 1); | ||
709 | if (my_empty_len >= iop_len) { | ||
710 | while (iop_len > 0) { | ||
711 | acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); | ||
712 | acb->rqbuf_lastindex++; | ||
713 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
714 | iop_data++; | ||
715 | iop_len--; | ||
716 | } | ||
717 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, | ||
718 | ®->inbound_doorbell); | ||
719 | } else | ||
720 | acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; | ||
721 | } | ||
722 | if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { | ||
723 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; | ||
724 | if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { | ||
725 | struct QBUFFER __iomem * pwbuffer = | ||
726 | (struct QBUFFER __iomem *) ®->message_wbuffer; | ||
727 | uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data; | ||
728 | int32_t allxfer_len = 0; | ||
729 | |||
730 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); | ||
731 | while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) | ||
732 | && (allxfer_len < 124)) { | ||
733 | writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); | ||
734 | acb->wqbuf_firstindex++; | ||
735 | acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | ||
736 | iop_data++; | ||
737 | allxfer_len++; | ||
738 | } | ||
739 | writel(allxfer_len, &pwbuffer->data_len); | ||
740 | writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, | ||
741 | ®->inbound_doorbell); | ||
742 | } | ||
743 | if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) | ||
744 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; | ||
745 | } | ||
746 | } | ||
747 | if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { | ||
748 | int id, lun; | ||
749 | /* | ||
750 | **************************************************************** | ||
751 | ** areca cdb command done | ||
752 | **************************************************************** | ||
753 | */ | ||
754 | while (1) { | ||
755 | if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) | ||
756 | break;/*chip FIFO no ccb for completion already*/ | ||
757 | /* check if command done with no error*/ | ||
758 | ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + | ||
759 | (flag_ccb << 5)); | ||
760 | if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { | ||
761 | if (ccb->startdone == ARCMSR_CCB_ABORTED) { | ||
762 | struct scsi_cmnd *abortcmd=ccb->pcmd; | ||
763 | if (abortcmd) { | ||
764 | abortcmd->result |= DID_ABORT >> 16; | ||
765 | arcmsr_ccb_complete(ccb, 1); | ||
766 | printk(KERN_NOTICE | ||
767 | "arcmsr%d: ccb='0x%p' isr got aborted command \n" | ||
768 | , acb->host->host_no, ccb); | ||
769 | } | ||
770 | continue; | ||
771 | } | ||
772 | printk(KERN_NOTICE | ||
773 | "arcmsr%d: isr get an illegal ccb command done acb='0x%p'" | ||
774 | "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x" | ||
775 | " ccboutstandingcount=%d \n" | ||
776 | , acb->host->host_no | ||
777 | , acb | ||
778 | , ccb | ||
779 | , ccb->acb | ||
780 | , ccb->startdone | ||
781 | , atomic_read(&acb->ccboutstandingcount)); | ||
782 | continue; | ||
783 | } | ||
784 | id = ccb->pcmd->device->id; | ||
785 | lun = ccb->pcmd->device->lun; | ||
786 | if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { | ||
787 | if (acb->devstate[id][lun] == ARECA_RAID_GONE) | ||
788 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
789 | ccb->pcmd->result = DID_OK << 16; | ||
790 | arcmsr_ccb_complete(ccb, 1); | ||
791 | } else { | ||
792 | switch(ccb->arcmsr_cdb.DeviceStatus) { | ||
793 | case ARCMSR_DEV_SELECT_TIMEOUT: { | ||
794 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
795 | ccb->pcmd->result = DID_TIME_OUT << 16; | ||
796 | arcmsr_ccb_complete(ccb, 1); | ||
797 | } | ||
798 | break; | ||
799 | case ARCMSR_DEV_ABORTED: | ||
800 | case ARCMSR_DEV_INIT_FAIL: { | ||
801 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
802 | ccb->pcmd->result = DID_BAD_TARGET << 16; | ||
803 | arcmsr_ccb_complete(ccb, 1); | ||
804 | } | ||
805 | break; | ||
806 | case ARCMSR_DEV_CHECK_CONDITION: { | ||
807 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
808 | arcmsr_report_sense_info(ccb); | ||
809 | arcmsr_ccb_complete(ccb, 1); | ||
810 | } | ||
811 | break; | ||
812 | default: | ||
813 | printk(KERN_NOTICE | ||
814 | "arcmsr%d: scsi id=%d lun=%d" | ||
815 | " isr get command error done," | ||
816 | "but got unknown DeviceStatus = 0x%x \n" | ||
817 | , acb->host->host_no | ||
818 | , id | ||
819 | , lun | ||
820 | , ccb->arcmsr_cdb.DeviceStatus); | ||
821 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
822 | ccb->pcmd->result = DID_NO_CONNECT << 16; | ||
823 | arcmsr_ccb_complete(ccb, 1); | ||
824 | break; | ||
825 | } | ||
826 | } | ||
827 | }/*drain reply FIFO*/ | ||
828 | } | ||
829 | if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) | ||
830 | return IRQ_NONE; | ||
831 | return IRQ_HANDLED; | ||
832 | } | ||
833 | |||
834 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) | ||
835 | { | ||
836 | if (acb) { | ||
837 | /* stop adapter background rebuild */ | ||
838 | if (acb->acb_flags & ACB_F_MSG_START_BGRB) { | ||
839 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | ||
840 | arcmsr_stop_adapter_bgrb(acb); | ||
841 | arcmsr_flush_adapter_cache(acb); | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | |||
846 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd) | ||
847 | { | ||
848 | struct MessageUnit __iomem *reg = acb->pmu; | ||
849 | struct CMD_MESSAGE_FIELD *pcmdmessagefld; | ||
850 | int retvalue = 0, transfer_len = 0; | ||
851 | char *buffer; | ||
852 | uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 | | ||
853 | (uint32_t ) cmd->cmnd[6] << 16 | | ||
854 | (uint32_t ) cmd->cmnd[7] << 8 | | ||
855 | (uint32_t ) cmd->cmnd[8]; | ||
856 | /* 4 bytes: Areca io control code */ | ||
857 | if (cmd->use_sg) { | ||
858 | struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer; | ||
859 | |||
860 | buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; | ||
861 | if (cmd->use_sg > 1) { | ||
862 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
863 | goto message_out; | ||
864 | } | ||
865 | transfer_len += sg->length; | ||
866 | } else { | ||
867 | buffer = cmd->request_buffer; | ||
868 | transfer_len = cmd->request_bufflen; | ||
869 | } | ||
870 | if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { | ||
871 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
872 | goto message_out; | ||
873 | } | ||
874 | pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; | ||
875 | switch(controlcode) { | ||
876 | case ARCMSR_MESSAGE_READ_RQBUFFER: { | ||
877 | unsigned long *ver_addr; | ||
878 | dma_addr_t buf_handle; | ||
879 | uint8_t *pQbuffer, *ptmpQbuffer; | ||
880 | int32_t allxfer_len = 0; | ||
881 | |||
882 | ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); | ||
883 | if (!ver_addr) { | ||
884 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
885 | goto message_out; | ||
886 | } | ||
887 | ptmpQbuffer = (uint8_t *) ver_addr; | ||
888 | while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) | ||
889 | && (allxfer_len < 1031)) { | ||
890 | pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; | ||
891 | memcpy(ptmpQbuffer, pQbuffer, 1); | ||
892 | acb->rqbuf_firstindex++; | ||
893 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | ||
894 | ptmpQbuffer++; | ||
895 | allxfer_len++; | ||
896 | } | ||
897 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
898 | struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) | ||
899 | ®->message_rbuffer; | ||
900 | uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; | ||
901 | int32_t iop_len; | ||
902 | |||
903 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
904 | iop_len = readl(&prbuffer->data_len); | ||
905 | while (iop_len > 0) { | ||
906 | acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); | ||
907 | acb->rqbuf_lastindex++; | ||
908 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
909 | iop_data++; | ||
910 | iop_len--; | ||
911 | } | ||
912 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, | ||
913 | ®->inbound_doorbell); | ||
914 | } | ||
915 | memcpy(pcmdmessagefld->messagedatabuffer, | ||
916 | (uint8_t *)ver_addr, allxfer_len); | ||
917 | pcmdmessagefld->cmdmessage.Length = allxfer_len; | ||
918 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | ||
919 | pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); | ||
920 | } | ||
921 | break; | ||
922 | case ARCMSR_MESSAGE_WRITE_WQBUFFER: { | ||
923 | unsigned long *ver_addr; | ||
924 | dma_addr_t buf_handle; | ||
925 | int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | ||
926 | uint8_t *pQbuffer, *ptmpuserbuffer; | ||
927 | |||
928 | ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); | ||
929 | if (!ver_addr) { | ||
930 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
931 | goto message_out; | ||
932 | } | ||
933 | ptmpuserbuffer = (uint8_t *)ver_addr; | ||
934 | user_len = pcmdmessagefld->cmdmessage.Length; | ||
935 | memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); | ||
936 | wqbuf_lastindex = acb->wqbuf_lastindex; | ||
937 | wqbuf_firstindex = acb->wqbuf_firstindex; | ||
938 | if (wqbuf_lastindex != wqbuf_firstindex) { | ||
939 | struct SENSE_DATA *sensebuffer = | ||
940 | (struct SENSE_DATA *)cmd->sense_buffer; | ||
941 | arcmsr_post_Qbuffer(acb); | ||
942 | /* has error report sensedata */ | ||
943 | sensebuffer->ErrorCode = 0x70; | ||
944 | sensebuffer->SenseKey = ILLEGAL_REQUEST; | ||
945 | sensebuffer->AdditionalSenseLength = 0x0A; | ||
946 | sensebuffer->AdditionalSenseCode = 0x20; | ||
947 | sensebuffer->Valid = 1; | ||
948 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
949 | } else { | ||
950 | my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) | ||
951 | &(ARCMSR_MAX_QBUFFER - 1); | ||
952 | if (my_empty_len >= user_len) { | ||
953 | while (user_len > 0) { | ||
954 | pQbuffer = | ||
955 | &acb->wqbuffer[acb->wqbuf_lastindex]; | ||
956 | memcpy(pQbuffer, ptmpuserbuffer, 1); | ||
957 | acb->wqbuf_lastindex++; | ||
958 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
959 | ptmpuserbuffer++; | ||
960 | user_len--; | ||
961 | } | ||
962 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | ||
963 | acb->acb_flags &= | ||
964 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; | ||
965 | arcmsr_post_Qbuffer(acb); | ||
966 | } | ||
967 | } else { | ||
968 | /* has error report sensedata */ | ||
969 | struct SENSE_DATA *sensebuffer = | ||
970 | (struct SENSE_DATA *)cmd->sense_buffer; | ||
971 | sensebuffer->ErrorCode = 0x70; | ||
972 | sensebuffer->SenseKey = ILLEGAL_REQUEST; | ||
973 | sensebuffer->AdditionalSenseLength = 0x0A; | ||
974 | sensebuffer->AdditionalSenseCode = 0x20; | ||
975 | sensebuffer->Valid = 1; | ||
976 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
977 | } | ||
978 | } | ||
979 | pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); | ||
980 | } | ||
981 | break; | ||
982 | case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { | ||
983 | uint8_t *pQbuffer = acb->rqbuffer; | ||
984 | |||
985 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
986 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
987 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, | ||
988 | ®->inbound_doorbell); | ||
989 | } | ||
990 | acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; | ||
991 | acb->rqbuf_firstindex = 0; | ||
992 | acb->rqbuf_lastindex = 0; | ||
993 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | ||
994 | pcmdmessagefld->cmdmessage.ReturnCode = | ||
995 | ARCMSR_MESSAGE_RETURNCODE_OK; | ||
996 | } | ||
997 | break; | ||
998 | case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { | ||
999 | uint8_t *pQbuffer = acb->wqbuffer; | ||
1000 | |||
1001 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
1002 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
1003 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK | ||
1004 | , ®->inbound_doorbell); | ||
1005 | } | ||
1006 | acb->acb_flags |= | ||
1007 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | | ||
1008 | ACB_F_MESSAGE_WQBUFFER_READED); | ||
1009 | acb->wqbuf_firstindex = 0; | ||
1010 | acb->wqbuf_lastindex = 0; | ||
1011 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | ||
1012 | pcmdmessagefld->cmdmessage.ReturnCode = | ||
1013 | ARCMSR_MESSAGE_RETURNCODE_OK; | ||
1014 | } | ||
1015 | break; | ||
1016 | case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { | ||
1017 | uint8_t *pQbuffer; | ||
1018 | |||
1019 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | ||
1020 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
1021 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK | ||
1022 | , ®->inbound_doorbell); | ||
1023 | } | ||
1024 | acb->acb_flags |= | ||
1025 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | ||
1026 | | ACB_F_MESSAGE_RQBUFFER_CLEARED | ||
1027 | | ACB_F_MESSAGE_WQBUFFER_READED); | ||
1028 | acb->rqbuf_firstindex = 0; | ||
1029 | acb->rqbuf_lastindex = 0; | ||
1030 | acb->wqbuf_firstindex = 0; | ||
1031 | acb->wqbuf_lastindex = 0; | ||
1032 | pQbuffer = acb->rqbuffer; | ||
1033 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | ||
1034 | pQbuffer = acb->wqbuffer; | ||
1035 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | ||
1036 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | ||
1037 | } | ||
1038 | break; | ||
1039 | case ARCMSR_MESSAGE_RETURN_CODE_3F: { | ||
1040 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; | ||
1041 | } | ||
1042 | break; | ||
1043 | case ARCMSR_MESSAGE_SAY_HELLO: { | ||
1044 | int8_t * hello_string = "Hello! I am ARCMSR"; | ||
1045 | |||
1046 | memcpy(pcmdmessagefld->messagedatabuffer, hello_string | ||
1047 | , (int16_t)strlen(hello_string)); | ||
1048 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | ||
1049 | } | ||
1050 | break; | ||
1051 | case ARCMSR_MESSAGE_SAY_GOODBYE: | ||
1052 | arcmsr_iop_parking(acb); | ||
1053 | break; | ||
1054 | case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: | ||
1055 | arcmsr_flush_adapter_cache(acb); | ||
1056 | break; | ||
1057 | default: | ||
1058 | retvalue = ARCMSR_MESSAGE_FAIL; | ||
1059 | } | ||
1060 | message_out: | ||
1061 | if (cmd->use_sg) { | ||
1062 | struct scatterlist *sg; | ||
1063 | |||
1064 | sg = (struct scatterlist *) cmd->request_buffer; | ||
1065 | kunmap_atomic(buffer - sg->offset, KM_IRQ0); | ||
1066 | } | ||
1067 | return retvalue; | ||
1068 | } | ||
1069 | |||
1070 | static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb) | ||
1071 | { | ||
1072 | struct list_head *head = &acb->ccb_free_list; | ||
1073 | struct CommandControlBlock *ccb = NULL; | ||
1074 | |||
1075 | if (!list_empty(head)) { | ||
1076 | ccb = list_entry(head->next, struct CommandControlBlock, list); | ||
1077 | list_del(head->next); | ||
1078 | } | ||
1079 | return ccb; | ||
1080 | } | ||
1081 | |||
1082 | static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, | ||
1083 | struct scsi_cmnd *cmd) | ||
1084 | { | ||
1085 | switch (cmd->cmnd[0]) { | ||
1086 | case INQUIRY: { | ||
1087 | unsigned char inqdata[36]; | ||
1088 | char *buffer; | ||
1089 | |||
1090 | if (cmd->device->lun) { | ||
1091 | cmd->result = (DID_TIME_OUT << 16); | ||
1092 | cmd->scsi_done(cmd); | ||
1093 | return; | ||
1094 | } | ||
1095 | inqdata[0] = TYPE_PROCESSOR; | ||
1096 | /* Periph Qualifier & Periph Dev Type */ | ||
1097 | inqdata[1] = 0; | ||
1098 | /* rem media bit & Dev Type Modifier */ | ||
1099 | inqdata[2] = 0; | ||
1100 | /* ISO,ECMA,& ANSI versions */ | ||
1101 | inqdata[4] = 31; | ||
1102 | /* length of additional data */ | ||
1103 | strncpy(&inqdata[8], "Areca ", 8); | ||
1104 | /* Vendor Identification */ | ||
1105 | strncpy(&inqdata[16], "RAID controller ", 16); | ||
1106 | /* Product Identification */ | ||
1107 | strncpy(&inqdata[32], "R001", 4); /* Product Revision */ | ||
1108 | if (cmd->use_sg) { | ||
1109 | struct scatterlist *sg; | ||
1110 | |||
1111 | sg = (struct scatterlist *) cmd->request_buffer; | ||
1112 | buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; | ||
1113 | } else { | ||
1114 | buffer = cmd->request_buffer; | ||
1115 | } | ||
1116 | memcpy(buffer, inqdata, sizeof(inqdata)); | ||
1117 | if (cmd->use_sg) { | ||
1118 | struct scatterlist *sg; | ||
1119 | |||
1120 | sg = (struct scatterlist *) cmd->request_buffer; | ||
1121 | kunmap_atomic(buffer - sg->offset, KM_IRQ0); | ||
1122 | } | ||
1123 | cmd->scsi_done(cmd); | ||
1124 | } | ||
1125 | break; | ||
1126 | case WRITE_BUFFER: | ||
1127 | case READ_BUFFER: { | ||
1128 | if (arcmsr_iop_message_xfer(acb, cmd)) | ||
1129 | cmd->result = (DID_ERROR << 16); | ||
1130 | cmd->scsi_done(cmd); | ||
1131 | } | ||
1132 | break; | ||
1133 | default: | ||
1134 | cmd->scsi_done(cmd); | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | static int arcmsr_queue_command(struct scsi_cmnd *cmd, | ||
1139 | void (* done)(struct scsi_cmnd *)) | ||
1140 | { | ||
1141 | struct Scsi_Host *host = cmd->device->host; | ||
1142 | struct AdapterControlBlock *acb = | ||
1143 | (struct AdapterControlBlock *) host->hostdata; | ||
1144 | struct CommandControlBlock *ccb; | ||
1145 | int target = cmd->device->id; | ||
1146 | int lun = cmd->device->lun; | ||
1147 | |||
1148 | cmd->scsi_done = done; | ||
1149 | cmd->host_scribble = NULL; | ||
1150 | cmd->result = 0; | ||
1151 | if (acb->acb_flags & ACB_F_BUS_RESET) { | ||
1152 | printk(KERN_NOTICE "arcmsr%d: bus reset" | ||
1153 | " and return busy \n" | ||
1154 | , acb->host->host_no); | ||
1155 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1156 | } | ||
1157 | if(target == 16) { | ||
1158 | /* virtual device for iop message transfer */ | ||
1159 | arcmsr_handle_virtual_command(acb, cmd); | ||
1160 | return 0; | ||
1161 | } | ||
1162 | if (acb->devstate[target][lun] == ARECA_RAID_GONE) { | ||
1163 | uint8_t block_cmd; | ||
1164 | |||
1165 | block_cmd = cmd->cmnd[0] & 0x0f; | ||
1166 | if (block_cmd == 0x08 || block_cmd == 0x0a) { | ||
1167 | printk(KERN_NOTICE | ||
1168 | "arcmsr%d: block 'read/write'" | ||
1169 | "command with gone raid volume" | ||
1170 | " Cmd=%2x, TargetId=%d, Lun=%d \n" | ||
1171 | , acb->host->host_no | ||
1172 | , cmd->cmnd[0] | ||
1173 | , target, lun); | ||
1174 | cmd->result = (DID_NO_CONNECT << 16); | ||
1175 | cmd->scsi_done(cmd); | ||
1176 | return 0; | ||
1177 | } | ||
1178 | } | ||
1179 | if (atomic_read(&acb->ccboutstandingcount) >= | ||
1180 | ARCMSR_MAX_OUTSTANDING_CMD) | ||
1181 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1182 | |||
1183 | ccb = arcmsr_get_freeccb(acb); | ||
1184 | if (!ccb) | ||
1185 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1186 | arcmsr_build_ccb(acb, ccb, cmd); | ||
1187 | arcmsr_post_ccb(acb, ccb); | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) | ||
1192 | { | ||
1193 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1194 | char *acb_firm_model = acb->firm_model; | ||
1195 | char *acb_firm_version = acb->firm_version; | ||
1196 | char __iomem *iop_firm_model = (char __iomem *) ®->message_rwbuffer[15]; | ||
1197 | char __iomem *iop_firm_version = (char __iomem *) ®->message_rwbuffer[17]; | ||
1198 | int count; | ||
1199 | |||
1200 | writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | ||
1201 | if (arcmsr_wait_msgint_ready(acb)) | ||
1202 | printk(KERN_NOTICE | ||
1203 | "arcmsr%d: wait " | ||
1204 | "'get adapter firmware miscellaneous data' timeout \n" | ||
1205 | , acb->host->host_no); | ||
1206 | count = 8; | ||
1207 | while (count) { | ||
1208 | *acb_firm_model = readb(iop_firm_model); | ||
1209 | acb_firm_model++; | ||
1210 | iop_firm_model++; | ||
1211 | count--; | ||
1212 | } | ||
1213 | count = 16; | ||
1214 | while (count) { | ||
1215 | *acb_firm_version = readb(iop_firm_version); | ||
1216 | acb_firm_version++; | ||
1217 | iop_firm_version++; | ||
1218 | count--; | ||
1219 | } | ||
1220 | printk(KERN_INFO | ||
1221 | "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" | ||
1222 | , acb->host->host_no | ||
1223 | , acb->firm_version); | ||
1224 | acb->firm_request_len = readl(®->message_rwbuffer[1]); | ||
1225 | acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); | ||
1226 | acb->firm_sdram_size = readl(®->message_rwbuffer[3]); | ||
1227 | acb->firm_hd_channels = readl(®->message_rwbuffer[4]); | ||
1228 | } | ||
1229 | |||
1230 | static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | ||
1231 | struct CommandControlBlock *poll_ccb) | ||
1232 | { | ||
1233 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1234 | struct CommandControlBlock *ccb; | ||
1235 | uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; | ||
1236 | int id, lun; | ||
1237 | |||
1238 | polling_ccb_retry: | ||
1239 | poll_count++; | ||
1240 | outbound_intstatus = readl(®->outbound_intstatus) | ||
1241 | & acb->outbound_int_enable; | ||
1242 | writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ | ||
1243 | while (1) { | ||
1244 | if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { | ||
1245 | if (poll_ccb_done) | ||
1246 | break; | ||
1247 | else { | ||
1248 | msleep(25); | ||
1249 | if (poll_count > 100) | ||
1250 | break; | ||
1251 | goto polling_ccb_retry; | ||
1252 | } | ||
1253 | } | ||
1254 | ccb = (struct CommandControlBlock *) | ||
1255 | (acb->vir2phy_offset + (flag_ccb << 5)); | ||
1256 | if ((ccb->acb != acb) || | ||
1257 | (ccb->startdone != ARCMSR_CCB_START)) { | ||
1258 | if ((ccb->startdone == ARCMSR_CCB_ABORTED) || | ||
1259 | (ccb == poll_ccb)) { | ||
1260 | printk(KERN_NOTICE | ||
1261 | "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'" | ||
1262 | " poll command abort successfully \n" | ||
1263 | , acb->host->host_no | ||
1264 | , ccb->pcmd->device->id | ||
1265 | , ccb->pcmd->device->lun | ||
1266 | , ccb); | ||
1267 | ccb->pcmd->result = DID_ABORT << 16; | ||
1268 | arcmsr_ccb_complete(ccb, 1); | ||
1269 | poll_ccb_done = 1; | ||
1270 | continue; | ||
1271 | } | ||
1272 | printk(KERN_NOTICE | ||
1273 | "arcmsr%d: polling get an illegal ccb" | ||
1274 | " command done ccb='0x%p'" | ||
1275 | "ccboutstandingcount=%d \n" | ||
1276 | , acb->host->host_no | ||
1277 | , ccb | ||
1278 | , atomic_read(&acb->ccboutstandingcount)); | ||
1279 | continue; | ||
1280 | } | ||
1281 | id = ccb->pcmd->device->id; | ||
1282 | lun = ccb->pcmd->device->lun; | ||
1283 | if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { | ||
1284 | if (acb->devstate[id][lun] == ARECA_RAID_GONE) | ||
1285 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
1286 | ccb->pcmd->result = DID_OK << 16; | ||
1287 | arcmsr_ccb_complete(ccb, 1); | ||
1288 | } else { | ||
1289 | switch(ccb->arcmsr_cdb.DeviceStatus) { | ||
1290 | case ARCMSR_DEV_SELECT_TIMEOUT: { | ||
1291 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
1292 | ccb->pcmd->result = DID_TIME_OUT << 16; | ||
1293 | arcmsr_ccb_complete(ccb, 1); | ||
1294 | } | ||
1295 | break; | ||
1296 | case ARCMSR_DEV_ABORTED: | ||
1297 | case ARCMSR_DEV_INIT_FAIL: { | ||
1298 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
1299 | ccb->pcmd->result = DID_BAD_TARGET << 16; | ||
1300 | arcmsr_ccb_complete(ccb, 1); | ||
1301 | } | ||
1302 | break; | ||
1303 | case ARCMSR_DEV_CHECK_CONDITION: { | ||
1304 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
1305 | arcmsr_report_sense_info(ccb); | ||
1306 | arcmsr_ccb_complete(ccb, 1); | ||
1307 | } | ||
1308 | break; | ||
1309 | default: | ||
1310 | printk(KERN_NOTICE | ||
1311 | "arcmsr%d: scsi id=%d lun=%d" | ||
1312 | " polling and getting command error done" | ||
1313 | "but got unknown DeviceStatus = 0x%x \n" | ||
1314 | , acb->host->host_no | ||
1315 | , id | ||
1316 | , lun | ||
1317 | , ccb->arcmsr_cdb.DeviceStatus); | ||
1318 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
1319 | ccb->pcmd->result = DID_BAD_TARGET << 16; | ||
1320 | arcmsr_ccb_complete(ccb, 1); | ||
1321 | break; | ||
1322 | } | ||
1323 | } | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | static void arcmsr_iop_init(struct AdapterControlBlock *acb) | ||
1328 | { | ||
1329 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1330 | uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0; | ||
1331 | |||
1332 | do { | ||
1333 | firmware_state = readl(®->outbound_msgaddr1); | ||
1334 | } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)); | ||
1335 | intmask_org = readl(®->outbound_intmask) | ||
1336 | | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; | ||
1337 | arcmsr_get_firmware_spec(acb); | ||
1338 | |||
1339 | acb->acb_flags |= ACB_F_MSG_START_BGRB; | ||
1340 | writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); | ||
1341 | if (arcmsr_wait_msgint_ready(acb)) { | ||
1342 | printk(KERN_NOTICE "arcmsr%d: " | ||
1343 | "wait 'start adapter background rebulid' timeout\n", | ||
1344 | acb->host->host_no); | ||
1345 | } | ||
1346 | |||
1347 | outbound_doorbell = readl(®->outbound_doorbell); | ||
1348 | writel(outbound_doorbell, ®->outbound_doorbell); | ||
1349 | writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | ||
1350 | mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | ||
1351 | | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); | ||
1352 | writel(intmask_org & mask, ®->outbound_intmask); | ||
1353 | acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; | ||
1354 | acb->acb_flags |= ACB_F_IOP_INITED; | ||
1355 | } | ||
1356 | |||
1357 | static void arcmsr_iop_reset(struct AdapterControlBlock *acb) | ||
1358 | { | ||
1359 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1360 | struct CommandControlBlock *ccb; | ||
1361 | uint32_t intmask_org; | ||
1362 | int i = 0; | ||
1363 | |||
1364 | if (atomic_read(&acb->ccboutstandingcount) != 0) { | ||
1365 | /* talk to iop 331 outstanding command aborted */ | ||
1366 | arcmsr_abort_allcmd(acb); | ||
1367 | /* wait for 3 sec for all command aborted*/ | ||
1368 | msleep_interruptible(3000); | ||
1369 | /* disable all outbound interrupt */ | ||
1370 | intmask_org = arcmsr_disable_outbound_ints(acb); | ||
1371 | /* clear all outbound posted Q */ | ||
1372 | for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) | ||
1373 | readl(®->outbound_queueport); | ||
1374 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | ||
1375 | ccb = acb->pccb_pool[i]; | ||
1376 | if ((ccb->startdone == ARCMSR_CCB_START) || | ||
1377 | (ccb->startdone == ARCMSR_CCB_ABORTED)) { | ||
1378 | ccb->startdone = ARCMSR_CCB_ABORTED; | ||
1379 | ccb->pcmd->result = DID_ABORT << 16; | ||
1380 | arcmsr_ccb_complete(ccb, 1); | ||
1381 | } | ||
1382 | } | ||
1383 | /* enable all outbound interrupt */ | ||
1384 | arcmsr_enable_outbound_ints(acb, intmask_org); | ||
1385 | } | ||
1386 | atomic_set(&acb->ccboutstandingcount, 0); | ||
1387 | } | ||
1388 | |||
1389 | static int arcmsr_bus_reset(struct scsi_cmnd *cmd) | ||
1390 | { | ||
1391 | struct AdapterControlBlock *acb = | ||
1392 | (struct AdapterControlBlock *)cmd->device->host->hostdata; | ||
1393 | int i; | ||
1394 | |||
1395 | acb->num_resets++; | ||
1396 | acb->acb_flags |= ACB_F_BUS_RESET; | ||
1397 | for (i = 0; i < 400; i++) { | ||
1398 | if (!atomic_read(&acb->ccboutstandingcount)) | ||
1399 | break; | ||
1400 | arcmsr_interrupt(acb); | ||
1401 | msleep(25); | ||
1402 | } | ||
1403 | arcmsr_iop_reset(acb); | ||
1404 | acb->acb_flags &= ~ACB_F_BUS_RESET; | ||
1405 | return SUCCESS; | ||
1406 | } | ||
1407 | |||
1408 | static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, | ||
1409 | struct CommandControlBlock *ccb) | ||
1410 | { | ||
1411 | u32 intmask; | ||
1412 | |||
1413 | ccb->startdone = ARCMSR_CCB_ABORTED; | ||
1414 | |||
1415 | /* | ||
1416 | ** Wait for 3 sec for all command done. | ||
1417 | */ | ||
1418 | msleep_interruptible(3000); | ||
1419 | |||
1420 | intmask = arcmsr_disable_outbound_ints(acb); | ||
1421 | arcmsr_polling_ccbdone(acb, ccb); | ||
1422 | arcmsr_enable_outbound_ints(acb, intmask); | ||
1423 | } | ||
1424 | |||
1425 | static int arcmsr_abort(struct scsi_cmnd *cmd) | ||
1426 | { | ||
1427 | struct AdapterControlBlock *acb = | ||
1428 | (struct AdapterControlBlock *)cmd->device->host->hostdata; | ||
1429 | int i = 0; | ||
1430 | |||
1431 | printk(KERN_NOTICE | ||
1432 | "arcmsr%d: abort device command of scsi id=%d lun=%d \n", | ||
1433 | acb->host->host_no, cmd->device->id, cmd->device->lun); | ||
1434 | acb->num_aborts++; | ||
1435 | |||
1436 | /* | ||
1437 | ************************************************ | ||
1438 | ** the all interrupt service routine is locked | ||
1439 | ** we need to handle it as soon as possible and exit | ||
1440 | ************************************************ | ||
1441 | */ | ||
1442 | if (!atomic_read(&acb->ccboutstandingcount)) | ||
1443 | return SUCCESS; | ||
1444 | |||
1445 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | ||
1446 | struct CommandControlBlock *ccb = acb->pccb_pool[i]; | ||
1447 | if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { | ||
1448 | arcmsr_abort_one_cmd(acb, ccb); | ||
1449 | break; | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | return SUCCESS; | ||
1454 | } | ||
1455 | |||
1456 | static const char *arcmsr_info(struct Scsi_Host *host) | ||
1457 | { | ||
1458 | struct AdapterControlBlock *acb = | ||
1459 | (struct AdapterControlBlock *) host->hostdata; | ||
1460 | static char buf[256]; | ||
1461 | char *type; | ||
1462 | int raid6 = 1; | ||
1463 | |||
1464 | switch (acb->pdev->device) { | ||
1465 | case PCI_DEVICE_ID_ARECA_1110: | ||
1466 | case PCI_DEVICE_ID_ARECA_1210: | ||
1467 | raid6 = 0; | ||
1468 | /*FALLTHRU*/ | ||
1469 | case PCI_DEVICE_ID_ARECA_1120: | ||
1470 | case PCI_DEVICE_ID_ARECA_1130: | ||
1471 | case PCI_DEVICE_ID_ARECA_1160: | ||
1472 | case PCI_DEVICE_ID_ARECA_1170: | ||
1473 | case PCI_DEVICE_ID_ARECA_1220: | ||
1474 | case PCI_DEVICE_ID_ARECA_1230: | ||
1475 | case PCI_DEVICE_ID_ARECA_1260: | ||
1476 | case PCI_DEVICE_ID_ARECA_1270: | ||
1477 | case PCI_DEVICE_ID_ARECA_1280: | ||
1478 | type = "SATA"; | ||
1479 | break; | ||
1480 | case PCI_DEVICE_ID_ARECA_1380: | ||
1481 | case PCI_DEVICE_ID_ARECA_1381: | ||
1482 | case PCI_DEVICE_ID_ARECA_1680: | ||
1483 | case PCI_DEVICE_ID_ARECA_1681: | ||
1484 | type = "SAS"; | ||
1485 | break; | ||
1486 | default: | ||
1487 | type = "X-TYPE"; | ||
1488 | break; | ||
1489 | } | ||
1490 | sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", | ||
1491 | type, raid6 ? "( RAID6 capable)" : "", | ||
1492 | ARCMSR_DRIVER_VERSION); | ||
1493 | return buf; | ||
1494 | } | ||
1495 | |||
1496 | |||