Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Adaptec AIC7xxx device driver for Linux. | |
3 | * | |
4 | * Copyright (c) 1994 John Aycock | |
5 | * The University of Calgary Department of Computer Science. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2, or (at your option) | |
10 | * any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; see the file COPYING. If not, write to | |
19 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | * | |
21 | * Copyright (c) 2000-2003 Adaptec Inc. | |
22 | * All rights reserved. | |
23 | * | |
24 | * Redistribution and use in source and binary forms, with or without | |
25 | * modification, are permitted provided that the following conditions | |
26 | * are met: | |
27 | * 1. Redistributions of source code must retain the above copyright | |
28 | * notice, this list of conditions, and the following disclaimer, | |
29 | * without modification. | |
30 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
31 | * substantially similar to the "NO WARRANTY" disclaimer below | |
32 | * ("Disclaimer") and any redistribution must be conditioned upon | |
33 | * including a substantially similar Disclaimer requirement for further | |
34 | * binary redistribution. | |
35 | * 3. Neither the names of the above-listed copyright holders nor the names | |
36 | * of any contributors may be used to endorse or promote products derived | |
37 | * from this software without specific prior written permission. | |
38 | * | |
39 | * Alternatively, this software may be distributed under the terms of the | |
40 | * GNU General Public License ("GPL") version 2 as published by the Free | |
41 | * Software Foundation. | |
42 | * | |
43 | * NO WARRANTY | |
44 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
45 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
46 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
47 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
48 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
52 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
53 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
54 | * POSSIBILITY OF SUCH DAMAGES. | |
55 | * | |
56 | * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#151 $ | |
57 | * | |
58 | */ | |
59 | #ifndef _AIC7XXX_LINUX_H_ | |
60 | #define _AIC7XXX_LINUX_H_ | |
61 | ||
013791ee | 62 | #include <linux/config.h> |
1da177e4 LT |
63 | #include <linux/types.h> |
64 | #include <linux/blkdev.h> | |
65 | #include <linux/delay.h> | |
66 | #include <linux/ioport.h> | |
67 | #include <linux/pci.h> | |
68 | #include <linux/smp_lock.h> | |
69 | #include <linux/version.h> | |
e4e360c3 | 70 | #include <linux/interrupt.h> |
1da177e4 | 71 | #include <linux/module.h> |
013791ee | 72 | #include <linux/slab.h> |
1da177e4 LT |
73 | #include <asm/byteorder.h> |
74 | #include <asm/io.h> | |
75 | ||
013791ee CH |
76 | #include <scsi/scsi.h> |
77 | #include <scsi/scsi_cmnd.h> | |
78 | #include <scsi/scsi_eh.h> | |
79 | #include <scsi/scsi_device.h> | |
80 | #include <scsi/scsi_host.h> | |
81 | #include <scsi/scsi_tcq.h> | |
b1abb4d6 JB |
82 | #include <scsi/scsi_transport.h> |
83 | #include <scsi/scsi_transport_spi.h> | |
1da177e4 LT |
84 | |
85 | /* Core SCSI definitions */ | |
86 | #define AIC_LIB_PREFIX ahc | |
1da177e4 LT |
87 | |
88 | /* Name space conflict with BSD queue macros */ | |
89 | #ifdef LIST_HEAD | |
90 | #undef LIST_HEAD | |
91 | #endif | |
92 | ||
93 | #include "cam.h" | |
94 | #include "queue.h" | |
95 | #include "scsi_message.h" | |
96 | #include "aiclib.h" | |
97 | ||
98 | /*********************************** Debugging ********************************/ | |
99 | #ifdef CONFIG_AIC7XXX_DEBUG_ENABLE | |
100 | #ifdef CONFIG_AIC7XXX_DEBUG_MASK | |
101 | #define AHC_DEBUG 1 | |
102 | #define AHC_DEBUG_OPTS CONFIG_AIC7XXX_DEBUG_MASK | |
103 | #else | |
104 | /* | |
105 | * Compile in debugging code, but do not enable any printfs. | |
106 | */ | |
107 | #define AHC_DEBUG 1 | |
108 | #endif | |
109 | /* No debugging code. */ | |
110 | #endif | |
111 | ||
112 | /************************* Forward Declarations *******************************/ | |
113 | struct ahc_softc; | |
114 | typedef struct pci_dev *ahc_dev_softc_t; | |
013791ee | 115 | typedef struct scsi_cmnd *ahc_io_ctx_t; |
1da177e4 LT |
116 | |
117 | /******************************* Byte Order ***********************************/ | |
118 | #define ahc_htobe16(x) cpu_to_be16(x) | |
119 | #define ahc_htobe32(x) cpu_to_be32(x) | |
120 | #define ahc_htobe64(x) cpu_to_be64(x) | |
121 | #define ahc_htole16(x) cpu_to_le16(x) | |
122 | #define ahc_htole32(x) cpu_to_le32(x) | |
123 | #define ahc_htole64(x) cpu_to_le64(x) | |
124 | ||
125 | #define ahc_be16toh(x) be16_to_cpu(x) | |
126 | #define ahc_be32toh(x) be32_to_cpu(x) | |
127 | #define ahc_be64toh(x) be64_to_cpu(x) | |
128 | #define ahc_le16toh(x) le16_to_cpu(x) | |
129 | #define ahc_le32toh(x) le32_to_cpu(x) | |
130 | #define ahc_le64toh(x) le64_to_cpu(x) | |
131 | ||
1da177e4 LT |
132 | /************************* Configuration Data *********************************/ |
133 | extern u_int aic7xxx_no_probe; | |
134 | extern u_int aic7xxx_allow_memio; | |
013791ee | 135 | extern struct scsi_host_template aic7xxx_driver_template; |
1da177e4 LT |
136 | |
137 | /***************************** Bus Space/DMA **********************************/ | |
138 | ||
139 | typedef uint32_t bus_size_t; | |
140 | ||
141 | typedef enum { | |
142 | BUS_SPACE_MEMIO, | |
143 | BUS_SPACE_PIO | |
144 | } bus_space_tag_t; | |
145 | ||
146 | typedef union { | |
147 | u_long ioport; | |
148 | volatile uint8_t __iomem *maddr; | |
149 | } bus_space_handle_t; | |
150 | ||
151 | typedef struct bus_dma_segment | |
152 | { | |
153 | dma_addr_t ds_addr; | |
154 | bus_size_t ds_len; | |
155 | } bus_dma_segment_t; | |
156 | ||
157 | struct ahc_linux_dma_tag | |
158 | { | |
159 | bus_size_t alignment; | |
160 | bus_size_t boundary; | |
161 | bus_size_t maxsize; | |
162 | }; | |
163 | typedef struct ahc_linux_dma_tag* bus_dma_tag_t; | |
164 | ||
7dfa0f26 | 165 | typedef dma_addr_t bus_dmamap_t; |
1da177e4 LT |
166 | |
167 | typedef int bus_dma_filter_t(void*, dma_addr_t); | |
168 | typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); | |
169 | ||
170 | #define BUS_DMA_WAITOK 0x0 | |
171 | #define BUS_DMA_NOWAIT 0x1 | |
172 | #define BUS_DMA_ALLOCNOW 0x2 | |
173 | #define BUS_DMA_LOAD_SEGS 0x4 /* | |
174 | * Argument is an S/G list not | |
175 | * a single buffer. | |
176 | */ | |
177 | ||
178 | #define BUS_SPACE_MAXADDR 0xFFFFFFFF | |
179 | #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF | |
180 | #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF | |
181 | ||
182 | int ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/, | |
183 | bus_size_t /*alignment*/, bus_size_t /*boundary*/, | |
184 | dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/, | |
185 | bus_dma_filter_t*/*filter*/, void */*filterarg*/, | |
186 | bus_size_t /*maxsize*/, int /*nsegments*/, | |
187 | bus_size_t /*maxsegsz*/, int /*flags*/, | |
188 | bus_dma_tag_t */*dma_tagp*/); | |
189 | ||
190 | void ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/); | |
191 | ||
192 | int ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/, | |
193 | void** /*vaddr*/, int /*flags*/, | |
194 | bus_dmamap_t* /*mapp*/); | |
195 | ||
196 | void ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/, | |
197 | void* /*vaddr*/, bus_dmamap_t /*map*/); | |
198 | ||
199 | void ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/, | |
200 | bus_dmamap_t /*map*/); | |
201 | ||
202 | int ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/, | |
203 | bus_dmamap_t /*map*/, void * /*buf*/, | |
204 | bus_size_t /*buflen*/, bus_dmamap_callback_t *, | |
205 | void */*callback_arg*/, int /*flags*/); | |
206 | ||
207 | int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); | |
208 | ||
209 | /* | |
210 | * Operations performed by ahc_dmamap_sync(). | |
211 | */ | |
212 | #define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ | |
213 | #define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ | |
214 | #define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ | |
215 | #define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ | |
216 | ||
217 | /* | |
218 | * XXX | |
219 | * ahc_dmamap_sync is only used on buffers allocated with | |
220 | * the pci_alloc_consistent() API. Although I'm not sure how | |
221 | * this works on architectures with a write buffer, Linux does | |
222 | * not have an API to sync "coherent" memory. Perhaps we need | |
223 | * to do an mb()? | |
224 | */ | |
225 | #define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) | |
226 | ||
227 | /************************** Timer DataStructures ******************************/ | |
228 | typedef struct timer_list ahc_timer_t; | |
229 | ||
230 | /********************************** Includes **********************************/ | |
231 | #ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT | |
232 | #define AIC_DEBUG_REGISTERS 1 | |
233 | #else | |
234 | #define AIC_DEBUG_REGISTERS 0 | |
235 | #endif | |
236 | #include "aic7xxx.h" | |
237 | ||
238 | /***************************** Timer Facilities *******************************/ | |
239 | #define ahc_timer_init init_timer | |
240 | #define ahc_timer_stop del_timer_sync | |
241 | typedef void ahc_linux_callback_t (u_long); | |
242 | static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec, | |
243 | ahc_callback_t *func, void *arg); | |
244 | static __inline void ahc_scb_timer_reset(struct scb *scb, u_int usec); | |
245 | ||
246 | static __inline void | |
247 | ahc_timer_reset(ahc_timer_t *timer, int usec, ahc_callback_t *func, void *arg) | |
248 | { | |
249 | struct ahc_softc *ahc; | |
250 | ||
251 | ahc = (struct ahc_softc *)arg; | |
252 | del_timer(timer); | |
253 | timer->data = (u_long)arg; | |
254 | timer->expires = jiffies + (usec * HZ)/1000000; | |
255 | timer->function = (ahc_linux_callback_t*)func; | |
256 | add_timer(timer); | |
257 | } | |
258 | ||
259 | static __inline void | |
260 | ahc_scb_timer_reset(struct scb *scb, u_int usec) | |
261 | { | |
262 | mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000); | |
263 | } | |
264 | ||
265 | /***************************** SMP support ************************************/ | |
266 | #include <linux/spinlock.h> | |
267 | ||
1da177e4 LT |
268 | #define AIC7XXX_DRIVER_VERSION "6.2.36" |
269 | ||
1da177e4 LT |
270 | /*************************** Device Data Structures ***************************/ |
271 | /* | |
272 | * A per probed device structure used to deal with some error recovery | |
273 | * scenarios that the Linux mid-layer code just doesn't know how to | |
274 | * handle. The structure allocated for a device only becomes persistent | |
275 | * after a successfully completed inquiry command to the target when | |
276 | * that inquiry data indicates a lun is present. | |
277 | */ | |
1da177e4 | 278 | typedef enum { |
1da177e4 | 279 | AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ |
1da177e4 LT |
280 | AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ |
281 | AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ | |
282 | AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ | |
1da177e4 LT |
283 | } ahc_linux_dev_flags; |
284 | ||
285 | struct ahc_linux_target; | |
286 | struct ahc_linux_device { | |
1da177e4 LT |
287 | /* |
288 | * The number of transactions currently | |
289 | * queued to the device. | |
290 | */ | |
291 | int active; | |
292 | ||
293 | /* | |
294 | * The currently allowed number of | |
295 | * transactions that can be queued to | |
296 | * the device. Must be signed for | |
297 | * conversion from tagged to untagged | |
298 | * mode where the device may have more | |
299 | * than one outstanding active transaction. | |
300 | */ | |
301 | int openings; | |
302 | ||
303 | /* | |
304 | * A positive count indicates that this | |
305 | * device's queue is halted. | |
306 | */ | |
307 | u_int qfrozen; | |
308 | ||
309 | /* | |
310 | * Cumulative command counter. | |
311 | */ | |
312 | u_long commands_issued; | |
313 | ||
314 | /* | |
315 | * The number of tagged transactions when | |
316 | * running at our current opening level | |
317 | * that have been successfully received by | |
318 | * this device since the last QUEUE FULL. | |
319 | */ | |
320 | u_int tag_success_count; | |
321 | #define AHC_TAG_SUCCESS_INTERVAL 50 | |
322 | ||
323 | ahc_linux_dev_flags flags; | |
324 | ||
1da177e4 LT |
325 | /* |
326 | * The high limit for the tags variable. | |
327 | */ | |
328 | u_int maxtags; | |
329 | ||
330 | /* | |
331 | * The computed number of tags outstanding | |
332 | * at the time of the last QUEUE FULL event. | |
333 | */ | |
334 | u_int tags_on_last_queuefull; | |
335 | ||
336 | /* | |
337 | * How many times we have seen a queue full | |
338 | * with the same number of tags. This is used | |
339 | * to stop our adaptive queue depth algorithm | |
340 | * on devices with a fixed number of tags. | |
341 | */ | |
342 | u_int last_queuefull_same_count; | |
343 | #define AHC_LOCK_TAGS_COUNT 50 | |
344 | ||
345 | /* | |
346 | * How many transactions have been queued | |
347 | * without the device going idle. We use | |
348 | * this statistic to determine when to issue | |
349 | * an ordered tag to prevent transaction | |
350 | * starvation. This statistic is only updated | |
351 | * if the AHC_DEV_PERIODIC_OTAG flag is set | |
352 | * on this device. | |
353 | */ | |
354 | u_int commands_since_idle_or_otag; | |
355 | #define AHC_OTAG_THRESH 500 | |
1da177e4 LT |
356 | }; |
357 | ||
1da177e4 | 358 | struct ahc_linux_target { |
b1abb4d6 | 359 | struct scsi_device *sdev[AHC_NUM_LUNS]; |
1da177e4 LT |
360 | struct ahc_transinfo last_tinfo; |
361 | struct ahc_softc *ahc; | |
1da177e4 LT |
362 | }; |
363 | ||
364 | /********************* Definitions Required by the Core ***********************/ | |
365 | /* | |
366 | * Number of SG segments we require. So long as the S/G segments for | |
367 | * a particular transaction are allocated in a physically contiguous | |
368 | * manner and are allocated below 4GB, the number of S/G segments is | |
369 | * unrestricted. | |
370 | */ | |
1da177e4 | 371 | #define AHC_NSEG 128 |
1da177e4 LT |
372 | |
373 | /* | |
374 | * Per-SCB OSM storage. | |
375 | */ | |
1da177e4 LT |
376 | struct scb_platform_data { |
377 | struct ahc_linux_device *dev; | |
378 | dma_addr_t buf_busaddr; | |
379 | uint32_t xfer_len; | |
380 | uint32_t sense_resid; /* Auto-Sense residual */ | |
1da177e4 LT |
381 | }; |
382 | ||
383 | /* | |
384 | * Define a structure used for each host adapter. All members are | |
385 | * aligned on a boundary >= the size of the member to honor the | |
386 | * alignment restrictions of the various platforms supported by | |
387 | * this driver. | |
388 | */ | |
1da177e4 LT |
389 | struct ahc_platform_data { |
390 | /* | |
391 | * Fields accessed from interrupt context. | |
392 | */ | |
b1abb4d6 | 393 | struct scsi_target *starget[AHC_NUM_TARGETS]; |
1da177e4 LT |
394 | |
395 | spinlock_t spin_lock; | |
1da177e4 | 396 | u_int qfrozen; |
1da177e4 LT |
397 | struct timer_list reset_timer; |
398 | struct semaphore eh_sem; | |
1da177e4 LT |
399 | struct Scsi_Host *host; /* pointer to scsi host */ |
400 | #define AHC_LINUX_NOIRQ ((uint32_t)~0) | |
401 | uint32_t irq; /* IRQ for this adapter */ | |
402 | uint32_t bios_address; | |
403 | uint32_t mem_busaddr; /* Mem Base Addr */ | |
8e45ebcc JB |
404 | |
405 | #define AHC_UP_EH_SEMAPHORE 0x1 | |
406 | uint32_t flags; | |
1da177e4 LT |
407 | }; |
408 | ||
409 | /************************** OS Utility Wrappers *******************************/ | |
410 | #define printf printk | |
411 | #define M_NOWAIT GFP_ATOMIC | |
412 | #define M_WAITOK 0 | |
413 | #define malloc(size, type, flags) kmalloc(size, flags) | |
414 | #define free(ptr, type) kfree(ptr) | |
415 | ||
416 | static __inline void ahc_delay(long); | |
417 | static __inline void | |
418 | ahc_delay(long usec) | |
419 | { | |
420 | /* | |
421 | * udelay on Linux can have problems for | |
422 | * multi-millisecond waits. Wait at most | |
423 | * 1024us per call. | |
424 | */ | |
425 | while (usec > 0) { | |
426 | udelay(usec % 1024); | |
427 | usec -= 1024; | |
428 | } | |
429 | } | |
430 | ||
431 | ||
432 | /***************************** Low Level I/O **********************************/ | |
433 | static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); | |
434 | static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val); | |
435 | static __inline void ahc_outsb(struct ahc_softc * ahc, long port, | |
436 | uint8_t *, int count); | |
437 | static __inline void ahc_insb(struct ahc_softc * ahc, long port, | |
438 | uint8_t *, int count); | |
439 | ||
440 | static __inline uint8_t | |
441 | ahc_inb(struct ahc_softc * ahc, long port) | |
442 | { | |
443 | uint8_t x; | |
444 | ||
445 | if (ahc->tag == BUS_SPACE_MEMIO) { | |
446 | x = readb(ahc->bsh.maddr + port); | |
447 | } else { | |
448 | x = inb(ahc->bsh.ioport + port); | |
449 | } | |
450 | mb(); | |
451 | return (x); | |
452 | } | |
453 | ||
454 | static __inline void | |
455 | ahc_outb(struct ahc_softc * ahc, long port, uint8_t val) | |
456 | { | |
457 | if (ahc->tag == BUS_SPACE_MEMIO) { | |
458 | writeb(val, ahc->bsh.maddr + port); | |
459 | } else { | |
460 | outb(val, ahc->bsh.ioport + port); | |
461 | } | |
462 | mb(); | |
463 | } | |
464 | ||
465 | static __inline void | |
466 | ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count) | |
467 | { | |
468 | int i; | |
469 | ||
470 | /* | |
471 | * There is probably a more efficient way to do this on Linux | |
472 | * but we don't use this for anything speed critical and this | |
473 | * should work. | |
474 | */ | |
475 | for (i = 0; i < count; i++) | |
476 | ahc_outb(ahc, port, *array++); | |
477 | } | |
478 | ||
479 | static __inline void | |
480 | ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count) | |
481 | { | |
482 | int i; | |
483 | ||
484 | /* | |
485 | * There is probably a more efficient way to do this on Linux | |
486 | * but we don't use this for anything speed critical and this | |
487 | * should work. | |
488 | */ | |
489 | for (i = 0; i < count; i++) | |
490 | *array++ = ahc_inb(ahc, port); | |
491 | } | |
492 | ||
493 | /**************************** Initialization **********************************/ | |
494 | int ahc_linux_register_host(struct ahc_softc *, | |
013791ee | 495 | struct scsi_host_template *); |
1da177e4 LT |
496 | |
497 | uint64_t ahc_linux_get_memsize(void); | |
498 | ||
499 | /*************************** Pretty Printing **********************************/ | |
500 | struct info_str { | |
501 | char *buffer; | |
502 | int length; | |
503 | off_t offset; | |
504 | int pos; | |
505 | }; | |
506 | ||
507 | void ahc_format_transinfo(struct info_str *info, | |
508 | struct ahc_transinfo *tinfo); | |
509 | ||
510 | /******************************** Locking *************************************/ | |
511 | /* Lock protecting internal data structures */ | |
1da177e4 LT |
512 | |
513 | static __inline void | |
514 | ahc_lockinit(struct ahc_softc *ahc) | |
515 | { | |
516 | spin_lock_init(&ahc->platform_data->spin_lock); | |
517 | } | |
518 | ||
519 | static __inline void | |
520 | ahc_lock(struct ahc_softc *ahc, unsigned long *flags) | |
521 | { | |
522 | spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags); | |
523 | } | |
524 | ||
525 | static __inline void | |
526 | ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) | |
527 | { | |
528 | spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags); | |
529 | } | |
530 | ||
1da177e4 LT |
531 | /******************************* PCI Definitions ******************************/ |
532 | /* | |
533 | * PCIM_xxx: mask to locate subfield in register | |
534 | * PCIR_xxx: config register offset | |
535 | * PCIC_xxx: device class | |
536 | * PCIS_xxx: device subclass | |
537 | * PCIP_xxx: device programming interface | |
538 | * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) | |
539 | * PCID_xxx: device ID | |
540 | */ | |
541 | #define PCIR_DEVVENDOR 0x00 | |
542 | #define PCIR_VENDOR 0x00 | |
543 | #define PCIR_DEVICE 0x02 | |
544 | #define PCIR_COMMAND 0x04 | |
545 | #define PCIM_CMD_PORTEN 0x0001 | |
546 | #define PCIM_CMD_MEMEN 0x0002 | |
547 | #define PCIM_CMD_BUSMASTEREN 0x0004 | |
548 | #define PCIM_CMD_MWRICEN 0x0010 | |
549 | #define PCIM_CMD_PERRESPEN 0x0040 | |
550 | #define PCIM_CMD_SERRESPEN 0x0100 | |
551 | #define PCIR_STATUS 0x06 | |
552 | #define PCIR_REVID 0x08 | |
553 | #define PCIR_PROGIF 0x09 | |
554 | #define PCIR_SUBCLASS 0x0a | |
555 | #define PCIR_CLASS 0x0b | |
556 | #define PCIR_CACHELNSZ 0x0c | |
557 | #define PCIR_LATTIMER 0x0d | |
558 | #define PCIR_HEADERTYPE 0x0e | |
559 | #define PCIM_MFDEV 0x80 | |
560 | #define PCIR_BIST 0x0f | |
561 | #define PCIR_CAP_PTR 0x34 | |
562 | ||
563 | /* config registers for header type 0 devices */ | |
564 | #define PCIR_MAPS 0x10 | |
565 | #define PCIR_SUBVEND_0 0x2c | |
566 | #define PCIR_SUBDEV_0 0x2e | |
567 | ||
568 | extern struct pci_driver aic7xxx_pci_driver; | |
569 | ||
570 | typedef enum | |
571 | { | |
572 | AHC_POWER_STATE_D0, | |
573 | AHC_POWER_STATE_D1, | |
574 | AHC_POWER_STATE_D2, | |
575 | AHC_POWER_STATE_D3 | |
576 | } ahc_power_state; | |
577 | ||
578 | /**************************** VL/EISA Routines ********************************/ | |
1da177e4 | 579 | #ifdef CONFIG_EISA |
1da177e4 LT |
580 | int ahc_linux_eisa_init(void); |
581 | void ahc_linux_eisa_exit(void); | |
582 | int aic7770_map_registers(struct ahc_softc *ahc, | |
583 | u_int port); | |
584 | int aic7770_map_int(struct ahc_softc *ahc, u_int irq); | |
585 | #else | |
586 | static inline int ahc_linux_eisa_init(void) { | |
587 | return -ENODEV; | |
588 | } | |
589 | static inline void ahc_linux_eisa_exit(void) { | |
590 | } | |
591 | #endif | |
592 | ||
593 | /******************************* PCI Routines *********************************/ | |
594 | #ifdef CONFIG_PCI | |
595 | int ahc_linux_pci_init(void); | |
596 | void ahc_linux_pci_exit(void); | |
597 | int ahc_pci_map_registers(struct ahc_softc *ahc); | |
598 | int ahc_pci_map_int(struct ahc_softc *ahc); | |
599 | ||
600 | static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci, | |
601 | int reg, int width); | |
602 | ||
603 | static __inline uint32_t | |
604 | ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width) | |
605 | { | |
606 | switch (width) { | |
607 | case 1: | |
608 | { | |
609 | uint8_t retval; | |
610 | ||
611 | pci_read_config_byte(pci, reg, &retval); | |
612 | return (retval); | |
613 | } | |
614 | case 2: | |
615 | { | |
616 | uint16_t retval; | |
617 | pci_read_config_word(pci, reg, &retval); | |
618 | return (retval); | |
619 | } | |
620 | case 4: | |
621 | { | |
622 | uint32_t retval; | |
623 | pci_read_config_dword(pci, reg, &retval); | |
624 | return (retval); | |
625 | } | |
626 | default: | |
627 | panic("ahc_pci_read_config: Read size too big"); | |
628 | /* NOTREACHED */ | |
629 | return (0); | |
630 | } | |
631 | } | |
632 | ||
633 | static __inline void ahc_pci_write_config(ahc_dev_softc_t pci, | |
634 | int reg, uint32_t value, | |
635 | int width); | |
636 | ||
637 | static __inline void | |
638 | ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) | |
639 | { | |
640 | switch (width) { | |
641 | case 1: | |
642 | pci_write_config_byte(pci, reg, value); | |
643 | break; | |
644 | case 2: | |
645 | pci_write_config_word(pci, reg, value); | |
646 | break; | |
647 | case 4: | |
648 | pci_write_config_dword(pci, reg, value); | |
649 | break; | |
650 | default: | |
651 | panic("ahc_pci_write_config: Write size too big"); | |
652 | /* NOTREACHED */ | |
653 | } | |
654 | } | |
655 | ||
656 | static __inline int ahc_get_pci_function(ahc_dev_softc_t); | |
657 | static __inline int | |
658 | ahc_get_pci_function(ahc_dev_softc_t pci) | |
659 | { | |
660 | return (PCI_FUNC(pci->devfn)); | |
661 | } | |
662 | ||
663 | static __inline int ahc_get_pci_slot(ahc_dev_softc_t); | |
664 | static __inline int | |
665 | ahc_get_pci_slot(ahc_dev_softc_t pci) | |
666 | { | |
667 | return (PCI_SLOT(pci->devfn)); | |
668 | } | |
669 | ||
670 | static __inline int ahc_get_pci_bus(ahc_dev_softc_t); | |
671 | static __inline int | |
672 | ahc_get_pci_bus(ahc_dev_softc_t pci) | |
673 | { | |
674 | return (pci->bus->number); | |
675 | } | |
676 | #else | |
677 | static inline int ahc_linux_pci_init(void) { | |
678 | return 0; | |
679 | } | |
680 | static inline void ahc_linux_pci_exit(void) { | |
681 | } | |
682 | #endif | |
683 | ||
684 | static __inline void ahc_flush_device_writes(struct ahc_softc *); | |
685 | static __inline void | |
686 | ahc_flush_device_writes(struct ahc_softc *ahc) | |
687 | { | |
688 | /* XXX Is this sufficient for all architectures??? */ | |
689 | ahc_inb(ahc, INTSTAT); | |
690 | } | |
691 | ||
692 | /**************************** Proc FS Support *********************************/ | |
1da177e4 LT |
693 | int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, |
694 | off_t, int, int); | |
1da177e4 LT |
695 | |
696 | /*************************** Domain Validation ********************************/ | |
1da177e4 | 697 | /*********************** Transaction Access Wrappers *************************/ |
013791ee | 698 | static __inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); |
1da177e4 | 699 | static __inline void ahc_set_transaction_status(struct scb *, uint32_t); |
013791ee | 700 | static __inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); |
1da177e4 | 701 | static __inline void ahc_set_scsi_status(struct scb *, uint32_t); |
013791ee | 702 | static __inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd); |
1da177e4 | 703 | static __inline uint32_t ahc_get_transaction_status(struct scb *); |
013791ee | 704 | static __inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd); |
1da177e4 LT |
705 | static __inline uint32_t ahc_get_scsi_status(struct scb *); |
706 | static __inline void ahc_set_transaction_tag(struct scb *, int, u_int); | |
707 | static __inline u_long ahc_get_transfer_length(struct scb *); | |
708 | static __inline int ahc_get_transfer_dir(struct scb *); | |
709 | static __inline void ahc_set_residual(struct scb *, u_long); | |
710 | static __inline void ahc_set_sense_residual(struct scb *scb, u_long resid); | |
711 | static __inline u_long ahc_get_residual(struct scb *); | |
712 | static __inline u_long ahc_get_sense_residual(struct scb *); | |
713 | static __inline int ahc_perform_autosense(struct scb *); | |
714 | static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *, | |
715 | struct scb *); | |
716 | static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *, | |
717 | struct ahc_devinfo *); | |
718 | static __inline void ahc_platform_scb_free(struct ahc_softc *ahc, | |
719 | struct scb *scb); | |
720 | static __inline void ahc_freeze_scb(struct scb *scb); | |
721 | ||
722 | static __inline | |
013791ee | 723 | void ahc_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) |
1da177e4 LT |
724 | { |
725 | cmd->result &= ~(CAM_STATUS_MASK << 16); | |
726 | cmd->result |= status << 16; | |
727 | } | |
728 | ||
729 | static __inline | |
730 | void ahc_set_transaction_status(struct scb *scb, uint32_t status) | |
731 | { | |
732 | ahc_cmd_set_transaction_status(scb->io_ctx,status); | |
733 | } | |
734 | ||
735 | static __inline | |
013791ee | 736 | void ahc_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) |
1da177e4 LT |
737 | { |
738 | cmd->result &= ~0xFFFF; | |
739 | cmd->result |= status; | |
740 | } | |
741 | ||
742 | static __inline | |
743 | void ahc_set_scsi_status(struct scb *scb, uint32_t status) | |
744 | { | |
745 | ahc_cmd_set_scsi_status(scb->io_ctx, status); | |
746 | } | |
747 | ||
748 | static __inline | |
013791ee | 749 | uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd) |
1da177e4 LT |
750 | { |
751 | return ((cmd->result >> 16) & CAM_STATUS_MASK); | |
752 | } | |
753 | ||
754 | static __inline | |
755 | uint32_t ahc_get_transaction_status(struct scb *scb) | |
756 | { | |
757 | return (ahc_cmd_get_transaction_status(scb->io_ctx)); | |
758 | } | |
759 | ||
760 | static __inline | |
013791ee | 761 | uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd) |
1da177e4 LT |
762 | { |
763 | return (cmd->result & 0xFFFF); | |
764 | } | |
765 | ||
766 | static __inline | |
767 | uint32_t ahc_get_scsi_status(struct scb *scb) | |
768 | { | |
769 | return (ahc_cmd_get_scsi_status(scb->io_ctx)); | |
770 | } | |
771 | ||
772 | static __inline | |
773 | void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) | |
774 | { | |
775 | /* | |
776 | * Nothing to do for linux as the incoming transaction | |
777 | * has no concept of tag/non tagged, etc. | |
778 | */ | |
779 | } | |
780 | ||
781 | static __inline | |
782 | u_long ahc_get_transfer_length(struct scb *scb) | |
783 | { | |
784 | return (scb->platform_data->xfer_len); | |
785 | } | |
786 | ||
787 | static __inline | |
788 | int ahc_get_transfer_dir(struct scb *scb) | |
789 | { | |
790 | return (scb->io_ctx->sc_data_direction); | |
791 | } | |
792 | ||
793 | static __inline | |
794 | void ahc_set_residual(struct scb *scb, u_long resid) | |
795 | { | |
796 | scb->io_ctx->resid = resid; | |
797 | } | |
798 | ||
799 | static __inline | |
800 | void ahc_set_sense_residual(struct scb *scb, u_long resid) | |
801 | { | |
802 | scb->platform_data->sense_resid = resid; | |
803 | } | |
804 | ||
805 | static __inline | |
806 | u_long ahc_get_residual(struct scb *scb) | |
807 | { | |
808 | return (scb->io_ctx->resid); | |
809 | } | |
810 | ||
811 | static __inline | |
812 | u_long ahc_get_sense_residual(struct scb *scb) | |
813 | { | |
814 | return (scb->platform_data->sense_resid); | |
815 | } | |
816 | ||
817 | static __inline | |
818 | int ahc_perform_autosense(struct scb *scb) | |
819 | { | |
820 | /* | |
821 | * We always perform autosense in Linux. | |
822 | * On other platforms this is set on a | |
823 | * per-transaction basis. | |
824 | */ | |
825 | return (1); | |
826 | } | |
827 | ||
828 | static __inline uint32_t | |
829 | ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb) | |
830 | { | |
831 | return (sizeof(struct scsi_sense_data)); | |
832 | } | |
833 | ||
834 | static __inline void | |
835 | ahc_notify_xfer_settings_change(struct ahc_softc *ahc, | |
836 | struct ahc_devinfo *devinfo) | |
837 | { | |
838 | /* Nothing to do here for linux */ | |
839 | } | |
840 | ||
841 | static __inline void | |
842 | ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb) | |
843 | { | |
1da177e4 LT |
844 | } |
845 | ||
846 | int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg); | |
847 | void ahc_platform_free(struct ahc_softc *ahc); | |
848 | void ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb); | |
849 | ||
850 | static __inline void | |
851 | ahc_freeze_scb(struct scb *scb) | |
852 | { | |
853 | if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { | |
854 | scb->io_ctx->result |= CAM_DEV_QFRZN << 16; | |
855 | scb->platform_data->dev->qfrozen++; | |
856 | } | |
857 | } | |
858 | ||
859 | void ahc_platform_set_tags(struct ahc_softc *ahc, | |
860 | struct ahc_devinfo *devinfo, ahc_queue_alg); | |
861 | int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, | |
862 | char channel, int lun, u_int tag, | |
863 | role_t role, uint32_t status); | |
864 | irqreturn_t | |
865 | ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); | |
866 | void ahc_platform_flushwork(struct ahc_softc *ahc); | |
1da177e4 LT |
867 | void ahc_done(struct ahc_softc*, struct scb*); |
868 | void ahc_send_async(struct ahc_softc *, char channel, | |
869 | u_int target, u_int lun, ac_code, void *); | |
870 | void ahc_print_path(struct ahc_softc *, struct scb *); | |
871 | void ahc_platform_dump_card_state(struct ahc_softc *ahc); | |
872 | ||
873 | #ifdef CONFIG_PCI | |
874 | #define AHC_PCI_CONFIG 1 | |
875 | #else | |
876 | #define AHC_PCI_CONFIG 0 | |
877 | #endif | |
878 | #define bootverbose aic7xxx_verbose | |
879 | extern u_int aic7xxx_verbose; | |
880 | #endif /* _AIC7XXX_LINUX_H_ */ |