Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Adaptec AIC79xx device driver for Linux. | |
3 | * | |
4 | * Copyright (c) 2000-2001 Adaptec Inc. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions, and the following disclaimer, | |
12 | * without modification. | |
13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
14 | * substantially similar to the "NO WARRANTY" disclaimer below | |
15 | * ("Disclaimer") and any redistribution must be conditioned upon | |
16 | * including a substantially similar Disclaimer requirement for further | |
17 | * binary redistribution. | |
18 | * 3. Neither the names of the above-listed copyright holders nor the names | |
19 | * of any contributors may be used to endorse or promote products derived | |
20 | * from this software without specific prior written permission. | |
21 | * | |
22 | * Alternatively, this software may be distributed under the terms of the | |
23 | * GNU General Public License ("GPL") version 2 as published by the Free | |
24 | * Software Foundation. | |
25 | * | |
26 | * NO WARRANTY | |
27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
37 | * POSSIBILITY OF SUCH DAMAGES. | |
38 | * | |
53467e63 | 39 | * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#166 $ |
1da177e4 LT |
40 | * |
41 | */ | |
42 | #ifndef _AIC79XX_LINUX_H_ | |
43 | #define _AIC79XX_LINUX_H_ | |
44 | ||
45 | #include <linux/types.h> | |
46 | #include <linux/blkdev.h> | |
47 | #include <linux/delay.h> | |
48 | #include <linux/ioport.h> | |
49 | #include <linux/pci.h> | |
50 | #include <linux/smp_lock.h> | |
73a25462 | 51 | #include <linux/interrupt.h> |
1da177e4 | 52 | #include <linux/module.h> |
73a25462 | 53 | #include <linux/slab.h> |
1da177e4 LT |
54 | #include <asm/byteorder.h> |
55 | #include <asm/io.h> | |
56 | ||
73a25462 HR |
57 | #include <scsi/scsi.h> |
58 | #include <scsi/scsi_cmnd.h> | |
59 | #include <scsi/scsi_eh.h> | |
60 | #include <scsi/scsi_device.h> | |
61 | #include <scsi/scsi_host.h> | |
62 | #include <scsi/scsi_tcq.h> | |
63 | #include <scsi/scsi_transport.h> | |
64 | #include <scsi/scsi_transport_spi.h> | |
1da177e4 LT |
65 | |
66 | /* Core SCSI definitions */ | |
67 | #define AIC_LIB_PREFIX ahd | |
1da177e4 LT |
68 | |
69 | /* Name space conflict with BSD queue macros */ | |
70 | #ifdef LIST_HEAD | |
71 | #undef LIST_HEAD | |
72 | #endif | |
73 | ||
74 | #include "cam.h" | |
75 | #include "queue.h" | |
76 | #include "scsi_message.h" | |
77 | #include "scsi_iu.h" | |
78 | #include "aiclib.h" | |
79 | ||
80 | /*********************************** Debugging ********************************/ | |
81 | #ifdef CONFIG_AIC79XX_DEBUG_ENABLE | |
82 | #ifdef CONFIG_AIC79XX_DEBUG_MASK | |
83 | #define AHD_DEBUG 1 | |
84 | #define AHD_DEBUG_OPTS CONFIG_AIC79XX_DEBUG_MASK | |
85 | #else | |
86 | /* | |
87 | * Compile in debugging code, but do not enable any printfs. | |
88 | */ | |
89 | #define AHD_DEBUG 1 | |
90 | #define AHD_DEBUG_OPTS 0 | |
91 | #endif | |
92 | /* No debugging code. */ | |
93 | #endif | |
94 | ||
95 | /********************************** Misc Macros *******************************/ | |
1da177e4 LT |
96 | #define powerof2(x) ((((x)-1)&(x))==0) |
97 | ||
98 | /************************* Forward Declarations *******************************/ | |
99 | struct ahd_softc; | |
100 | typedef struct pci_dev *ahd_dev_softc_t; | |
73a25462 | 101 | typedef struct scsi_cmnd *ahd_io_ctx_t; |
1da177e4 LT |
102 | |
103 | /******************************* Byte Order ***********************************/ | |
104 | #define ahd_htobe16(x) cpu_to_be16(x) | |
105 | #define ahd_htobe32(x) cpu_to_be32(x) | |
106 | #define ahd_htobe64(x) cpu_to_be64(x) | |
107 | #define ahd_htole16(x) cpu_to_le16(x) | |
108 | #define ahd_htole32(x) cpu_to_le32(x) | |
109 | #define ahd_htole64(x) cpu_to_le64(x) | |
110 | ||
111 | #define ahd_be16toh(x) be16_to_cpu(x) | |
112 | #define ahd_be32toh(x) be32_to_cpu(x) | |
113 | #define ahd_be64toh(x) be64_to_cpu(x) | |
114 | #define ahd_le16toh(x) le16_to_cpu(x) | |
115 | #define ahd_le32toh(x) le32_to_cpu(x) | |
116 | #define ahd_le64toh(x) le64_to_cpu(x) | |
117 | ||
1da177e4 LT |
118 | /************************* Configuration Data *********************************/ |
119 | extern uint32_t aic79xx_allow_memio; | |
73a25462 | 120 | extern struct scsi_host_template aic79xx_driver_template; |
1da177e4 LT |
121 | |
122 | /***************************** Bus Space/DMA **********************************/ | |
123 | ||
124 | typedef uint32_t bus_size_t; | |
125 | ||
126 | typedef enum { | |
127 | BUS_SPACE_MEMIO, | |
128 | BUS_SPACE_PIO | |
129 | } bus_space_tag_t; | |
130 | ||
131 | typedef union { | |
132 | u_long ioport; | |
133 | volatile uint8_t __iomem *maddr; | |
134 | } bus_space_handle_t; | |
135 | ||
136 | typedef struct bus_dma_segment | |
137 | { | |
138 | dma_addr_t ds_addr; | |
139 | bus_size_t ds_len; | |
140 | } bus_dma_segment_t; | |
141 | ||
142 | struct ahd_linux_dma_tag | |
143 | { | |
144 | bus_size_t alignment; | |
145 | bus_size_t boundary; | |
146 | bus_size_t maxsize; | |
147 | }; | |
148 | typedef struct ahd_linux_dma_tag* bus_dma_tag_t; | |
149 | ||
73a25462 | 150 | typedef dma_addr_t bus_dmamap_t; |
1da177e4 LT |
151 | |
152 | typedef int bus_dma_filter_t(void*, dma_addr_t); | |
153 | typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); | |
154 | ||
155 | #define BUS_DMA_WAITOK 0x0 | |
156 | #define BUS_DMA_NOWAIT 0x1 | |
157 | #define BUS_DMA_ALLOCNOW 0x2 | |
158 | #define BUS_DMA_LOAD_SEGS 0x4 /* | |
159 | * Argument is an S/G list not | |
160 | * a single buffer. | |
161 | */ | |
162 | ||
163 | #define BUS_SPACE_MAXADDR 0xFFFFFFFF | |
164 | #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF | |
165 | #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF | |
166 | ||
167 | int ahd_dma_tag_create(struct ahd_softc *, bus_dma_tag_t /*parent*/, | |
168 | bus_size_t /*alignment*/, bus_size_t /*boundary*/, | |
169 | dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/, | |
170 | bus_dma_filter_t*/*filter*/, void */*filterarg*/, | |
171 | bus_size_t /*maxsize*/, int /*nsegments*/, | |
172 | bus_size_t /*maxsegsz*/, int /*flags*/, | |
173 | bus_dma_tag_t */*dma_tagp*/); | |
174 | ||
175 | void ahd_dma_tag_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/); | |
176 | ||
177 | int ahd_dmamem_alloc(struct ahd_softc *, bus_dma_tag_t /*dmat*/, | |
178 | void** /*vaddr*/, int /*flags*/, | |
179 | bus_dmamap_t* /*mapp*/); | |
180 | ||
181 | void ahd_dmamem_free(struct ahd_softc *, bus_dma_tag_t /*dmat*/, | |
182 | void* /*vaddr*/, bus_dmamap_t /*map*/); | |
183 | ||
184 | void ahd_dmamap_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/, | |
185 | bus_dmamap_t /*map*/); | |
186 | ||
187 | int ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t /*dmat*/, | |
188 | bus_dmamap_t /*map*/, void * /*buf*/, | |
189 | bus_size_t /*buflen*/, bus_dmamap_callback_t *, | |
190 | void */*callback_arg*/, int /*flags*/); | |
191 | ||
192 | int ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t); | |
193 | ||
194 | /* | |
195 | * Operations performed by ahd_dmamap_sync(). | |
196 | */ | |
197 | #define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ | |
198 | #define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ | |
199 | #define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ | |
200 | #define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ | |
201 | ||
202 | /* | |
203 | * XXX | |
204 | * ahd_dmamap_sync is only used on buffers allocated with | |
205 | * the pci_alloc_consistent() API. Although I'm not sure how | |
206 | * this works on architectures with a write buffer, Linux does | |
207 | * not have an API to sync "coherent" memory. Perhaps we need | |
208 | * to do an mb()? | |
209 | */ | |
210 | #define ahd_dmamap_sync(ahd, dma_tag, dmamap, offset, len, op) | |
211 | ||
212 | /************************** Timer DataStructures ******************************/ | |
213 | typedef struct timer_list ahd_timer_t; | |
214 | ||
215 | /********************************** Includes **********************************/ | |
216 | #ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT | |
217 | #define AIC_DEBUG_REGISTERS 1 | |
218 | #else | |
219 | #define AIC_DEBUG_REGISTERS 0 | |
220 | #endif | |
221 | #include "aic79xx.h" | |
222 | ||
223 | /***************************** Timer Facilities *******************************/ | |
224 | #define ahd_timer_init init_timer | |
225 | #define ahd_timer_stop del_timer_sync | |
226 | typedef void ahd_linux_callback_t (u_long); | |
73a25462 | 227 | static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec, |
1da177e4 | 228 | ahd_callback_t *func, void *arg); |
1da177e4 LT |
229 | |
230 | static __inline void | |
73a25462 | 231 | ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg) |
1da177e4 LT |
232 | { |
233 | struct ahd_softc *ahd; | |
234 | ||
235 | ahd = (struct ahd_softc *)arg; | |
236 | del_timer(timer); | |
237 | timer->data = (u_long)arg; | |
238 | timer->expires = jiffies + (usec * HZ)/1000000; | |
239 | timer->function = (ahd_linux_callback_t*)func; | |
240 | add_timer(timer); | |
241 | } | |
242 | ||
1da177e4 LT |
243 | /***************************** SMP support ************************************/ |
244 | #include <linux/spinlock.h> | |
245 | ||
cd2f1e69 | 246 | #define AIC79XX_DRIVER_VERSION "3.0" |
1da177e4 | 247 | |
1da177e4 LT |
248 | /*************************** Device Data Structures ***************************/ |
249 | /* | |
250 | * A per probed device structure used to deal with some error recovery | |
251 | * scenarios that the Linux mid-layer code just doesn't know how to | |
252 | * handle. The structure allocated for a device only becomes persistent | |
253 | * after a successfully completed inquiry command to the target when | |
254 | * that inquiry data indicates a lun is present. | |
255 | */ | |
60a13213 | 256 | |
1da177e4 | 257 | typedef enum { |
1da177e4 | 258 | AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ |
1da177e4 LT |
259 | AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ |
260 | AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ | |
261 | AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ | |
1da177e4 LT |
262 | } ahd_linux_dev_flags; |
263 | ||
1da177e4 LT |
264 | struct ahd_linux_device { |
265 | TAILQ_ENTRY(ahd_linux_device) links; | |
1da177e4 LT |
266 | |
267 | /* | |
268 | * The number of transactions currently | |
269 | * queued to the device. | |
270 | */ | |
271 | int active; | |
272 | ||
273 | /* | |
274 | * The currently allowed number of | |
275 | * transactions that can be queued to | |
276 | * the device. Must be signed for | |
277 | * conversion from tagged to untagged | |
278 | * mode where the device may have more | |
279 | * than one outstanding active transaction. | |
280 | */ | |
281 | int openings; | |
282 | ||
283 | /* | |
284 | * A positive count indicates that this | |
285 | * device's queue is halted. | |
286 | */ | |
287 | u_int qfrozen; | |
288 | ||
289 | /* | |
290 | * Cumulative command counter. | |
291 | */ | |
292 | u_long commands_issued; | |
293 | ||
294 | /* | |
295 | * The number of tagged transactions when | |
296 | * running at our current opening level | |
297 | * that have been successfully received by | |
298 | * this device since the last QUEUE FULL. | |
299 | */ | |
300 | u_int tag_success_count; | |
301 | #define AHD_TAG_SUCCESS_INTERVAL 50 | |
302 | ||
303 | ahd_linux_dev_flags flags; | |
304 | ||
305 | /* | |
306 | * Per device timer. | |
307 | */ | |
308 | struct timer_list timer; | |
309 | ||
310 | /* | |
311 | * The high limit for the tags variable. | |
312 | */ | |
313 | u_int maxtags; | |
314 | ||
315 | /* | |
316 | * The computed number of tags outstanding | |
317 | * at the time of the last QUEUE FULL event. | |
318 | */ | |
319 | u_int tags_on_last_queuefull; | |
320 | ||
321 | /* | |
322 | * How many times we have seen a queue full | |
323 | * with the same number of tags. This is used | |
324 | * to stop our adaptive queue depth algorithm | |
325 | * on devices with a fixed number of tags. | |
326 | */ | |
327 | u_int last_queuefull_same_count; | |
328 | #define AHD_LOCK_TAGS_COUNT 50 | |
329 | ||
330 | /* | |
331 | * How many transactions have been queued | |
332 | * without the device going idle. We use | |
333 | * this statistic to determine when to issue | |
334 | * an ordered tag to prevent transaction | |
335 | * starvation. This statistic is only updated | |
336 | * if the AHD_DEV_PERIODIC_OTAG flag is set | |
337 | * on this device. | |
338 | */ | |
339 | u_int commands_since_idle_or_otag; | |
340 | #define AHD_OTAG_THRESH 500 | |
1da177e4 LT |
341 | }; |
342 | ||
1da177e4 LT |
343 | /********************* Definitions Required by the Core ***********************/ |
344 | /* | |
345 | * Number of SG segments we require. So long as the S/G segments for | |
346 | * a particular transaction are allocated in a physically contiguous | |
347 | * manner and are allocated below 4GB, the number of S/G segments is | |
348 | * unrestricted. | |
349 | */ | |
1da177e4 | 350 | #define AHD_NSEG 128 |
1da177e4 LT |
351 | |
352 | /* | |
353 | * Per-SCB OSM storage. | |
354 | */ | |
1da177e4 LT |
355 | struct scb_platform_data { |
356 | struct ahd_linux_device *dev; | |
357 | dma_addr_t buf_busaddr; | |
358 | uint32_t xfer_len; | |
359 | uint32_t sense_resid; /* Auto-Sense residual */ | |
1da177e4 LT |
360 | }; |
361 | ||
362 | /* | |
363 | * Define a structure used for each host adapter. All members are | |
364 | * aligned on a boundary >= the size of the member to honor the | |
365 | * alignment restrictions of the various platforms supported by | |
366 | * this driver. | |
367 | */ | |
1da177e4 LT |
368 | struct ahd_platform_data { |
369 | /* | |
370 | * Fields accessed from interrupt context. | |
371 | */ | |
73a25462 | 372 | struct scsi_target *starget[AHD_NUM_TARGETS]; |
1da177e4 LT |
373 | |
374 | spinlock_t spin_lock; | |
7b22da38 | 375 | struct completion *eh_done; |
1da177e4 LT |
376 | struct Scsi_Host *host; /* pointer to scsi host */ |
377 | #define AHD_LINUX_NOIRQ ((uint32_t)~0) | |
378 | uint32_t irq; /* IRQ for this adapter */ | |
379 | uint32_t bios_address; | |
380 | uint32_t mem_busaddr; /* Mem Base Addr */ | |
1da177e4 LT |
381 | }; |
382 | ||
383 | /************************** OS Utility Wrappers *******************************/ | |
384 | #define printf printk | |
385 | #define M_NOWAIT GFP_ATOMIC | |
386 | #define M_WAITOK 0 | |
387 | #define malloc(size, type, flags) kmalloc(size, flags) | |
388 | #define free(ptr, type) kfree(ptr) | |
389 | ||
390 | static __inline void ahd_delay(long); | |
391 | static __inline void | |
392 | ahd_delay(long usec) | |
393 | { | |
394 | /* | |
395 | * udelay on Linux can have problems for | |
396 | * multi-millisecond waits. Wait at most | |
397 | * 1024us per call. | |
398 | */ | |
399 | while (usec > 0) { | |
400 | udelay(usec % 1024); | |
401 | usec -= 1024; | |
402 | } | |
403 | } | |
404 | ||
405 | ||
406 | /***************************** Low Level I/O **********************************/ | |
407 | static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port); | |
408 | static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port); | |
409 | static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val); | |
410 | static __inline void ahd_outw_atomic(struct ahd_softc * ahd, | |
411 | long port, uint16_t val); | |
412 | static __inline void ahd_outsb(struct ahd_softc * ahd, long port, | |
413 | uint8_t *, int count); | |
414 | static __inline void ahd_insb(struct ahd_softc * ahd, long port, | |
415 | uint8_t *, int count); | |
416 | ||
417 | static __inline uint8_t | |
418 | ahd_inb(struct ahd_softc * ahd, long port) | |
419 | { | |
420 | uint8_t x; | |
421 | ||
422 | if (ahd->tags[0] == BUS_SPACE_MEMIO) { | |
423 | x = readb(ahd->bshs[0].maddr + port); | |
424 | } else { | |
425 | x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); | |
426 | } | |
427 | mb(); | |
428 | return (x); | |
429 | } | |
430 | ||
431 | static __inline uint16_t | |
432 | ahd_inw_atomic(struct ahd_softc * ahd, long port) | |
433 | { | |
434 | uint8_t x; | |
435 | ||
436 | if (ahd->tags[0] == BUS_SPACE_MEMIO) { | |
437 | x = readw(ahd->bshs[0].maddr + port); | |
438 | } else { | |
439 | x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); | |
440 | } | |
441 | mb(); | |
442 | return (x); | |
443 | } | |
444 | ||
445 | static __inline void | |
446 | ahd_outb(struct ahd_softc * ahd, long port, uint8_t val) | |
447 | { | |
448 | if (ahd->tags[0] == BUS_SPACE_MEMIO) { | |
449 | writeb(val, ahd->bshs[0].maddr + port); | |
450 | } else { | |
451 | outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); | |
452 | } | |
453 | mb(); | |
454 | } | |
455 | ||
456 | static __inline void | |
457 | ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val) | |
458 | { | |
459 | if (ahd->tags[0] == BUS_SPACE_MEMIO) { | |
460 | writew(val, ahd->bshs[0].maddr + port); | |
461 | } else { | |
462 | outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); | |
463 | } | |
464 | mb(); | |
465 | } | |
466 | ||
467 | static __inline void | |
468 | ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count) | |
469 | { | |
470 | int i; | |
471 | ||
472 | /* | |
473 | * There is probably a more efficient way to do this on Linux | |
474 | * but we don't use this for anything speed critical and this | |
475 | * should work. | |
476 | */ | |
477 | for (i = 0; i < count; i++) | |
478 | ahd_outb(ahd, port, *array++); | |
479 | } | |
480 | ||
481 | static __inline void | |
482 | ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count) | |
483 | { | |
484 | int i; | |
485 | ||
486 | /* | |
487 | * There is probably a more efficient way to do this on Linux | |
488 | * but we don't use this for anything speed critical and this | |
489 | * should work. | |
490 | */ | |
491 | for (i = 0; i < count; i++) | |
492 | *array++ = ahd_inb(ahd, port); | |
493 | } | |
494 | ||
495 | /**************************** Initialization **********************************/ | |
496 | int ahd_linux_register_host(struct ahd_softc *, | |
73a25462 | 497 | struct scsi_host_template *); |
1da177e4 LT |
498 | |
499 | uint64_t ahd_linux_get_memsize(void); | |
500 | ||
501 | /*************************** Pretty Printing **********************************/ | |
502 | struct info_str { | |
503 | char *buffer; | |
504 | int length; | |
505 | off_t offset; | |
506 | int pos; | |
507 | }; | |
508 | ||
509 | void ahd_format_transinfo(struct info_str *info, | |
510 | struct ahd_transinfo *tinfo); | |
511 | ||
512 | /******************************** Locking *************************************/ | |
1da177e4 LT |
513 | static __inline void |
514 | ahd_lockinit(struct ahd_softc *ahd) | |
515 | { | |
516 | spin_lock_init(&ahd->platform_data->spin_lock); | |
517 | } | |
518 | ||
519 | static __inline void | |
520 | ahd_lock(struct ahd_softc *ahd, unsigned long *flags) | |
521 | { | |
522 | spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags); | |
523 | } | |
524 | ||
525 | static __inline void | |
526 | ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) | |
527 | { | |
528 | spin_unlock_irqrestore(&ahd->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 | /****************************** PCI-X definitions *****************************/ | |
569 | #define PCIXR_COMMAND 0x96 | |
570 | #define PCIXR_DEVADDR 0x98 | |
571 | #define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */ | |
572 | #define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */ | |
573 | #define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */ | |
574 | #define PCIXR_STATUS 0x9A | |
575 | #define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */ | |
576 | #define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */ | |
577 | #define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */ | |
578 | #define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */ | |
579 | #define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */ | |
580 | #define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */ | |
581 | #define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */ | |
582 | #define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ | |
583 | #define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ | |
584 | ||
585 | extern struct pci_driver aic79xx_pci_driver; | |
586 | ||
587 | typedef enum | |
588 | { | |
589 | AHD_POWER_STATE_D0, | |
590 | AHD_POWER_STATE_D1, | |
591 | AHD_POWER_STATE_D2, | |
592 | AHD_POWER_STATE_D3 | |
593 | } ahd_power_state; | |
594 | ||
595 | void ahd_power_state_change(struct ahd_softc *ahd, | |
596 | ahd_power_state new_state); | |
597 | ||
598 | /******************************* PCI Routines *********************************/ | |
599 | int ahd_linux_pci_init(void); | |
600 | void ahd_linux_pci_exit(void); | |
601 | int ahd_pci_map_registers(struct ahd_softc *ahd); | |
602 | int ahd_pci_map_int(struct ahd_softc *ahd); | |
603 | ||
604 | static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci, | |
605 | int reg, int width); | |
606 | ||
607 | static __inline uint32_t | |
608 | ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width) | |
609 | { | |
610 | switch (width) { | |
611 | case 1: | |
612 | { | |
613 | uint8_t retval; | |
614 | ||
615 | pci_read_config_byte(pci, reg, &retval); | |
616 | return (retval); | |
617 | } | |
618 | case 2: | |
619 | { | |
620 | uint16_t retval; | |
621 | pci_read_config_word(pci, reg, &retval); | |
622 | return (retval); | |
623 | } | |
624 | case 4: | |
625 | { | |
626 | uint32_t retval; | |
627 | pci_read_config_dword(pci, reg, &retval); | |
628 | return (retval); | |
629 | } | |
630 | default: | |
631 | panic("ahd_pci_read_config: Read size too big"); | |
632 | /* NOTREACHED */ | |
633 | return (0); | |
634 | } | |
635 | } | |
636 | ||
637 | static __inline void ahd_pci_write_config(ahd_dev_softc_t pci, | |
638 | int reg, uint32_t value, | |
639 | int width); | |
640 | ||
641 | static __inline void | |
642 | ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width) | |
643 | { | |
644 | switch (width) { | |
645 | case 1: | |
646 | pci_write_config_byte(pci, reg, value); | |
647 | break; | |
648 | case 2: | |
649 | pci_write_config_word(pci, reg, value); | |
650 | break; | |
651 | case 4: | |
652 | pci_write_config_dword(pci, reg, value); | |
653 | break; | |
654 | default: | |
655 | panic("ahd_pci_write_config: Write size too big"); | |
656 | /* NOTREACHED */ | |
657 | } | |
658 | } | |
659 | ||
660 | static __inline int ahd_get_pci_function(ahd_dev_softc_t); | |
661 | static __inline int | |
662 | ahd_get_pci_function(ahd_dev_softc_t pci) | |
663 | { | |
664 | return (PCI_FUNC(pci->devfn)); | |
665 | } | |
666 | ||
667 | static __inline int ahd_get_pci_slot(ahd_dev_softc_t); | |
668 | static __inline int | |
669 | ahd_get_pci_slot(ahd_dev_softc_t pci) | |
670 | { | |
671 | return (PCI_SLOT(pci->devfn)); | |
672 | } | |
673 | ||
674 | static __inline int ahd_get_pci_bus(ahd_dev_softc_t); | |
675 | static __inline int | |
676 | ahd_get_pci_bus(ahd_dev_softc_t pci) | |
677 | { | |
678 | return (pci->bus->number); | |
679 | } | |
680 | ||
681 | static __inline void ahd_flush_device_writes(struct ahd_softc *); | |
682 | static __inline void | |
683 | ahd_flush_device_writes(struct ahd_softc *ahd) | |
684 | { | |
685 | /* XXX Is this sufficient for all architectures??? */ | |
686 | ahd_inb(ahd, INTSTAT); | |
687 | } | |
688 | ||
689 | /**************************** Proc FS Support *********************************/ | |
1da177e4 LT |
690 | int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, |
691 | off_t, int, int); | |
1da177e4 | 692 | |
1da177e4 | 693 | /*********************** Transaction Access Wrappers **************************/ |
73a25462 | 694 | static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); |
1da177e4 | 695 | static __inline void ahd_set_transaction_status(struct scb *, uint32_t); |
73a25462 | 696 | static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); |
1da177e4 | 697 | static __inline void ahd_set_scsi_status(struct scb *, uint32_t); |
73a25462 | 698 | static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); |
1da177e4 | 699 | static __inline uint32_t ahd_get_transaction_status(struct scb *); |
73a25462 | 700 | static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); |
1da177e4 LT |
701 | static __inline uint32_t ahd_get_scsi_status(struct scb *); |
702 | static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); | |
703 | static __inline u_long ahd_get_transfer_length(struct scb *); | |
704 | static __inline int ahd_get_transfer_dir(struct scb *); | |
705 | static __inline void ahd_set_residual(struct scb *, u_long); | |
706 | static __inline void ahd_set_sense_residual(struct scb *scb, u_long resid); | |
707 | static __inline u_long ahd_get_residual(struct scb *); | |
708 | static __inline u_long ahd_get_sense_residual(struct scb *); | |
709 | static __inline int ahd_perform_autosense(struct scb *); | |
710 | static __inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *, | |
711 | struct scb *); | |
712 | static __inline void ahd_notify_xfer_settings_change(struct ahd_softc *, | |
713 | struct ahd_devinfo *); | |
714 | static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, | |
715 | struct scb *scb); | |
716 | static __inline void ahd_freeze_scb(struct scb *scb); | |
717 | ||
718 | static __inline | |
73a25462 | 719 | void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) |
1da177e4 LT |
720 | { |
721 | cmd->result &= ~(CAM_STATUS_MASK << 16); | |
722 | cmd->result |= status << 16; | |
723 | } | |
724 | ||
725 | static __inline | |
726 | void ahd_set_transaction_status(struct scb *scb, uint32_t status) | |
727 | { | |
728 | ahd_cmd_set_transaction_status(scb->io_ctx,status); | |
729 | } | |
730 | ||
731 | static __inline | |
73a25462 | 732 | void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) |
1da177e4 LT |
733 | { |
734 | cmd->result &= ~0xFFFF; | |
735 | cmd->result |= status; | |
736 | } | |
737 | ||
738 | static __inline | |
739 | void ahd_set_scsi_status(struct scb *scb, uint32_t status) | |
740 | { | |
741 | ahd_cmd_set_scsi_status(scb->io_ctx, status); | |
742 | } | |
743 | ||
744 | static __inline | |
73a25462 | 745 | uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) |
1da177e4 LT |
746 | { |
747 | return ((cmd->result >> 16) & CAM_STATUS_MASK); | |
748 | } | |
749 | ||
750 | static __inline | |
751 | uint32_t ahd_get_transaction_status(struct scb *scb) | |
752 | { | |
753 | return (ahd_cmd_get_transaction_status(scb->io_ctx)); | |
754 | } | |
755 | ||
756 | static __inline | |
73a25462 | 757 | uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) |
1da177e4 LT |
758 | { |
759 | return (cmd->result & 0xFFFF); | |
760 | } | |
761 | ||
762 | static __inline | |
763 | uint32_t ahd_get_scsi_status(struct scb *scb) | |
764 | { | |
765 | return (ahd_cmd_get_scsi_status(scb->io_ctx)); | |
766 | } | |
767 | ||
768 | static __inline | |
769 | void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type) | |
770 | { | |
771 | /* | |
772 | * Nothing to do for linux as the incoming transaction | |
773 | * has no concept of tag/non tagged, etc. | |
774 | */ | |
775 | } | |
776 | ||
777 | static __inline | |
778 | u_long ahd_get_transfer_length(struct scb *scb) | |
779 | { | |
780 | return (scb->platform_data->xfer_len); | |
781 | } | |
782 | ||
783 | static __inline | |
784 | int ahd_get_transfer_dir(struct scb *scb) | |
785 | { | |
786 | return (scb->io_ctx->sc_data_direction); | |
787 | } | |
788 | ||
789 | static __inline | |
790 | void ahd_set_residual(struct scb *scb, u_long resid) | |
791 | { | |
792 | scb->io_ctx->resid = resid; | |
793 | } | |
794 | ||
795 | static __inline | |
796 | void ahd_set_sense_residual(struct scb *scb, u_long resid) | |
797 | { | |
798 | scb->platform_data->sense_resid = resid; | |
799 | } | |
800 | ||
801 | static __inline | |
802 | u_long ahd_get_residual(struct scb *scb) | |
803 | { | |
804 | return (scb->io_ctx->resid); | |
805 | } | |
806 | ||
807 | static __inline | |
808 | u_long ahd_get_sense_residual(struct scb *scb) | |
809 | { | |
810 | return (scb->platform_data->sense_resid); | |
811 | } | |
812 | ||
813 | static __inline | |
814 | int ahd_perform_autosense(struct scb *scb) | |
815 | { | |
816 | /* | |
817 | * We always perform autosense in Linux. | |
818 | * On other platforms this is set on a | |
819 | * per-transaction basis. | |
820 | */ | |
821 | return (1); | |
822 | } | |
823 | ||
824 | static __inline uint32_t | |
825 | ahd_get_sense_bufsize(struct ahd_softc *ahd, struct scb *scb) | |
826 | { | |
827 | return (sizeof(struct scsi_sense_data)); | |
828 | } | |
829 | ||
830 | static __inline void | |
831 | ahd_notify_xfer_settings_change(struct ahd_softc *ahd, | |
832 | struct ahd_devinfo *devinfo) | |
833 | { | |
834 | /* Nothing to do here for linux */ | |
835 | } | |
836 | ||
837 | static __inline void | |
838 | ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb) | |
839 | { | |
840 | ahd->flags &= ~AHD_RESOURCE_SHORTAGE; | |
841 | } | |
842 | ||
843 | int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg); | |
844 | void ahd_platform_free(struct ahd_softc *ahd); | |
845 | void ahd_platform_init(struct ahd_softc *ahd); | |
846 | void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); | |
847 | void ahd_freeze_simq(struct ahd_softc *ahd); | |
848 | void ahd_release_simq(struct ahd_softc *ahd); | |
849 | ||
850 | static __inline void | |
851 | ahd_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 | ||
f89d0a4e | 859 | void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, |
1da177e4 LT |
860 | struct ahd_devinfo *devinfo, ahd_queue_alg); |
861 | int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, | |
862 | char channel, int lun, u_int tag, | |
863 | role_t role, uint32_t status); | |
864 | irqreturn_t | |
7d12e780 | 865 | ahd_linux_isr(int irq, void *dev_id); |
1da177e4 LT |
866 | void ahd_done(struct ahd_softc*, struct scb*); |
867 | void ahd_send_async(struct ahd_softc *, char channel, | |
f89d0a4e | 868 | u_int target, u_int lun, ac_code); |
1da177e4 | 869 | void ahd_print_path(struct ahd_softc *, struct scb *); |
1da177e4 LT |
870 | |
871 | #ifdef CONFIG_PCI | |
872 | #define AHD_PCI_CONFIG 1 | |
873 | #else | |
874 | #define AHD_PCI_CONFIG 0 | |
875 | #endif | |
876 | #define bootverbose aic79xx_verbose | |
877 | extern uint32_t aic79xx_verbose; | |
878 | ||
879 | #endif /* _AIC79XX_LINUX_H_ */ |