File: /usr/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c

1     /*
2      * Linux driver attachment glue for aic7770 based controllers.
3      *
4      * Copyright (c) 2000 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. The name of the author may not be used to endorse or promote products
14      *    derived from this software without specific prior written permission.
15      *
16      * Alternatively, this software may be distributed under the terms of the
17      * GNU General Public License ("GPL").
18      *
19      * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20      * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21      * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22      * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23      * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24      * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25      * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26      * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27      * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29      * SUCH DAMAGE.
30      *
31      * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $
32      */
33     
34     #include "aic7xxx_osm.h"
35     
36     #define MINSLOT			1
37     #define NUMSLOTS		16
38     #define IDOFFSET		0x80
39     
40     int
41     aic7770_linux_probe(Scsi_Host_Template *template)
42     {
43     #if defined(__i386__) || defined(__alpha__)
44     	struct aic7770_identity *entry;
45     	struct ahc_softc *ahc;
46     	int i, slot;
47     	int eisaBase;
48     	int found;
49     
50     	if (aic7xxx_no_probe)
51     		return (0);
52     
53     	eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
54     	found = 0;
55     	for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
56     		uint32_t eisa_id;
57     		size_t	 id_size;
58     
59     		if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0)
60     			continue;
61     
62     		eisa_id = 0;
63     		id_size = sizeof(eisa_id);
64     		for (i = 0; i < 4; i++) {
65     			/* VLcards require priming*/
66     			outb(0x80 + i, eisaBase + IDOFFSET);
67     			eisa_id |= inb(eisaBase + IDOFFSET + i)
68     				   << ((id_size-i-1) * 8);
69     		}
70     		if (eisa_id & 0x80000000)
71     			continue;  /* no EISA card in slot */
72     
73     		entry = aic7770_find_device(eisa_id);
74     		if (entry != NULL) {
75     			char	 buf[80];
76     			char	*name;
77     			int	 error;
78     
79     			/*
80     			 * Allocate a softc for this card and
81     			 * set it up for attachment by our
82     			 * common detect routine.
83     			 */
84     			sprintf(buf, "ahc_eisa:%d", slot);
85     			name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
86     			if (name == NULL)
87     				break;
88     			strcpy(name, buf);
89     			ahc = ahc_alloc(template, name);
90     			if (ahc == NULL) {
91     				/*
92     				 * If we can't allocate this one,
93     				 * chances are we won't be able to
94     				 * allocate future card structures.
95     				 */
96     				break;
97     			}
98     			ahc->tag = BUS_SPACE_PIO;
99     			ahc->bsh.ioport = eisaBase;
100     			error = aic7770_config(ahc, entry);
101     			if (error != 0) {
102     				ahc_free(ahc);
103     				continue;
104     			}
105     			found++;
106     		}
107     	}
108     	return (found);
109     #else
110     	return (0);
111     #endif
112     }
113     
114     int
115     aic7770_map_registers(struct ahc_softc *ahc)
116     {
117     	/*
118     	 * Lock out other contenders for our i/o space.
119     	 */
120     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
121     	request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx");
122     #else
123     	if (request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx") == 0)
124     		return (ENOMEM);
125     #endif
126     
127     	return (0);
128     }
129     
130     int
131     aic7770_map_int(struct ahc_softc *ahc, u_int irq)
132     {
133     	int error;
134     	int shared;
135     
136     	shared = 0;
137     	if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
138     		shared = SA_SHIRQ;
139     
140     	ahc->platform_data->irq = irq;
141     	error = request_irq(ahc->platform_data->irq, ahc_linux_isr,
142     			    shared, "aic7xxx", ahc);
143     	
144     	return (-error);
145     }
146