• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Written by Martin Kolinek, February 1996
3  *
4  * Changes:
5  *
6  *	Chris Beauregard July 28th, 1996
7  *	- Fixed up integrated SCSI detection
8  *
9  *	Chris Beauregard August 3rd, 1996
10  *	- Made mca_info local
11  *	- Made integrated registers accessible through standard function calls
12  *	- Added name field
13  *	- More sanity checking
14  *
15  *	Chris Beauregard August 9th, 1996
16  *	- Rewrote /proc/mca
17  *
18  *	Chris Beauregard January 7th, 1997
19  *	- Added basic NMI-processing
20  *	- Added more information to mca_info structure
21  *
22  *	David Weinehall October 12th, 1998
23  *	- Made a lot of cleaning up in the source
24  *	- Added use of save_flags / restore_flags
25  *	- Added the 'driver_loaded' flag in MCA_adapter
26  *	- Added an alternative implemention of ZP Gu's mca_find_unused_adapter
27  *
28  *	David Weinehall March 24th, 1999
29  *	- Fixed the output of 'Driver Installed' in /proc/mca/pos
30  *	- Made the Integrated Video & SCSI show up even if they have id 0000
31  *
32  *	Alexander Viro November 9th, 1999
33  *	- Switched to regular procfs methods
34  *
35  *	Alfred Arnold & David Weinehall August 23rd, 2000
36  *	- Added support for Planar POS-registers
37  */
38 
39 #include <linux/module.h>
40 #include <linux/types.h>
41 #include <linux/errno.h>
42 #include <linux/kernel.h>
43 #include <linux/mca.h>
44 #include <linux/kprobes.h>
45 #include <linux/slab.h>
46 #include <asm/io.h>
47 #include <linux/proc_fs.h>
48 #include <linux/mman.h>
49 #include <linux/mm.h>
50 #include <linux/pagemap.h>
51 #include <linux/ioport.h>
52 #include <asm/uaccess.h>
53 #include <linux/init.h>
54 
55 static unsigned char which_scsi;
56 
57 int MCA_bus;
58 EXPORT_SYMBOL(MCA_bus);
59 
60 /*
61  * Motherboard register spinlock. Untested on SMP at the moment, but
62  * are there any MCA SMP boxes?
63  *
64  * Yes - Alan
65  */
66 static DEFINE_SPINLOCK(mca_lock);
67 
68 /* Build the status info for the adapter */
69 
mca_configure_adapter_status(struct mca_device * mca_dev)70 static void mca_configure_adapter_status(struct mca_device *mca_dev)
71 {
72 	mca_dev->status = MCA_ADAPTER_NONE;
73 
74 	mca_dev->pos_id = mca_dev->pos[0]
75 		+ (mca_dev->pos[1] << 8);
76 
77 	if (!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) {
78 
79 		/*
80 		 * id = 0x0000 usually indicates hardware failure,
81 		 * however, ZP Gu (zpg@castle.net> reports that his 9556
82 		 * has 0x0000 as id and everything still works. There
83 		 * also seem to be an adapter with id = 0x0000; the
84 		 * NCR Parallel Bus Memory Card. Until this is confirmed,
85 		 * however, this code will stay.
86 		 */
87 
88 		mca_dev->status = MCA_ADAPTER_ERROR;
89 
90 		return;
91 	} else if (mca_dev->pos_id != 0xffff) {
92 
93 		/*
94 		 * 0xffff usually indicates that there's no adapter,
95 		 * however, some integrated adapters may have 0xffff as
96 		 * their id and still be valid. Examples are on-board
97 		 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
98 		 * and possibly also the 95 ULTIMEDIA.
99 		 */
100 
101 		mca_dev->status = MCA_ADAPTER_NORMAL;
102 	}
103 
104 	if ((mca_dev->pos_id == 0xffff ||
105 	    mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) {
106 		int j;
107 
108 		for (j = 2; j < 8; j++) {
109 			if (mca_dev->pos[j] != 0xff) {
110 				mca_dev->status = MCA_ADAPTER_NORMAL;
111 				break;
112 			}
113 		}
114 	}
115 
116 	if (!(mca_dev->pos[2] & MCA_ENABLED)) {
117 
118 		/* enabled bit is in POS 2 */
119 
120 		mca_dev->status = MCA_ADAPTER_DISABLED;
121 	}
122 } /* mca_configure_adapter_status */
123 
124 /*--------------------------------------------------------------------*/
125 
126 static struct resource mca_standard_resources[] = {
127 	{ .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" },
128 	{ .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" },
129 	{ .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" },
130 	{ .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" },
131 	{ .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" },
132 	{ .start = 0x96, .end = 0x97, .name = "POS (MCA)" },
133 	{ .start = 0x100, .end = 0x107, .name = "POS (MCA)" }
134 };
135 
136 #define MCA_STANDARD_RESOURCES	ARRAY_SIZE(mca_standard_resources)
137 
138 /*
139  *	mca_read_and_store_pos - read the POS registers into a memory buffer
140  *      @pos: a char pointer to 8 bytes, contains the POS register value on
141  *            successful return
142  *
143  *	Returns 1 if a card actually exists (i.e. the pos isn't
144  *	all 0xff) or 0 otherwise
145  */
mca_read_and_store_pos(unsigned char * pos)146 static int mca_read_and_store_pos(unsigned char *pos)
147 {
148 	int j;
149 	int found = 0;
150 
151 	for (j = 0; j < 8; j++) {
152 		pos[j] = inb_p(MCA_POS_REG(j));
153 		if (pos[j] != 0xff) {
154 			/* 0xff all across means no device. 0x00 means
155 			 * something's broken, but a device is
156 			 * probably there.  However, if you get 0x00
157 			 * from a motherboard register it won't matter
158 			 * what we find.  For the record, on the
159 			 * 57SLC, the integrated SCSI adapter has
160 			 * 0xffff for the adapter ID, but nonzero for
161 			 * other registers.  */
162 
163 			found = 1;
164 		}
165 	}
166 	return found;
167 }
168 
mca_pc_read_pos(struct mca_device * mca_dev,int reg)169 static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg)
170 {
171 	unsigned char byte;
172 	unsigned long flags;
173 
174 	if (reg < 0 || reg >= 8)
175 		return 0;
176 
177 	spin_lock_irqsave(&mca_lock, flags);
178 	if (mca_dev->pos_register) {
179 		/* Disable adapter setup, enable motherboard setup */
180 
181 		outb_p(0, MCA_ADAPTER_SETUP_REG);
182 		outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
183 
184 		byte = inb_p(MCA_POS_REG(reg));
185 		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
186 	} else {
187 
188 		/* Make sure motherboard setup is off */
189 
190 		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
191 
192 		/* Read the appropriate register */
193 
194 		outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG);
195 		byte = inb_p(MCA_POS_REG(reg));
196 		outb_p(0, MCA_ADAPTER_SETUP_REG);
197 	}
198 	spin_unlock_irqrestore(&mca_lock, flags);
199 
200 	mca_dev->pos[reg] = byte;
201 
202 	return byte;
203 }
204 
mca_pc_write_pos(struct mca_device * mca_dev,int reg,unsigned char byte)205 static void mca_pc_write_pos(struct mca_device *mca_dev, int reg,
206 			     unsigned char byte)
207 {
208 	unsigned long flags;
209 
210 	if (reg < 0 || reg >= 8)
211 		return;
212 
213 	spin_lock_irqsave(&mca_lock, flags);
214 
215 	/* Make sure motherboard setup is off */
216 
217 	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
218 
219 	/* Read in the appropriate register */
220 
221 	outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG);
222 	outb_p(byte, MCA_POS_REG(reg));
223 	outb_p(0, MCA_ADAPTER_SETUP_REG);
224 
225 	spin_unlock_irqrestore(&mca_lock, flags);
226 
227 	/* Update the global register list, while we have the byte */
228 
229 	mca_dev->pos[reg] = byte;
230 
231 }
232 
233 /* for the primary MCA bus, we have identity transforms */
mca_dummy_transform_irq(struct mca_device * mca_dev,int irq)234 static int mca_dummy_transform_irq(struct mca_device *mca_dev, int irq)
235 {
236 	return irq;
237 }
238 
mca_dummy_transform_ioport(struct mca_device * mca_dev,int port)239 static int mca_dummy_transform_ioport(struct mca_device *mca_dev, int port)
240 {
241 	return port;
242 }
243 
mca_dummy_transform_memory(struct mca_device * mca_dev,void * mem)244 static void *mca_dummy_transform_memory(struct mca_device *mca_dev, void *mem)
245 {
246 	return mem;
247 }
248 
249 
mca_init(void)250 static int __init mca_init(void)
251 {
252 	unsigned int i, j;
253 	struct mca_device *mca_dev;
254 	unsigned char pos[8];
255 	short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00};
256 	struct mca_bus *bus;
257 
258 	/*
259 	 * WARNING: Be careful when making changes here. Putting an adapter
260 	 * and the motherboard simultaneously into setup mode may result in
261 	 * damage to chips (according to The Indispensable PC Hardware Book
262 	 * by Hans-Peter Messmer). Also, we disable system interrupts (so
263 	 * that we are not disturbed in the middle of this).
264 	 */
265 
266 	/* Make sure the MCA bus is present */
267 
268 	if (mca_system_init()) {
269 		printk(KERN_ERR "MCA bus system initialisation failed\n");
270 		return -ENODEV;
271 	}
272 
273 	if (!MCA_bus)
274 		return -ENODEV;
275 
276 	printk(KERN_INFO "Micro Channel bus detected.\n");
277 
278 	/* All MCA systems have at least a primary bus */
279 	bus = mca_attach_bus(MCA_PRIMARY_BUS);
280 	if (!bus)
281 		goto out_nomem;
282 	bus->default_dma_mask = 0xffffffffLL;
283 	bus->f.mca_write_pos = mca_pc_write_pos;
284 	bus->f.mca_read_pos = mca_pc_read_pos;
285 	bus->f.mca_transform_irq = mca_dummy_transform_irq;
286 	bus->f.mca_transform_ioport = mca_dummy_transform_ioport;
287 	bus->f.mca_transform_memory = mca_dummy_transform_memory;
288 
289 	/* get the motherboard device */
290 	mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
291 	if (unlikely(!mca_dev))
292 		goto out_nomem;
293 
294 	/*
295 	 * We do not expect many MCA interrupts during initialization,
296 	 * but let us be safe:
297 	 */
298 	spin_lock_irq(&mca_lock);
299 
300 	/* Make sure adapter setup is off */
301 
302 	outb_p(0, MCA_ADAPTER_SETUP_REG);
303 
304 	/* Read motherboard POS registers */
305 
306 	mca_dev->pos_register = 0x7f;
307 	outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
308 	mca_dev->name[0] = 0;
309 	mca_read_and_store_pos(mca_dev->pos);
310 	mca_configure_adapter_status(mca_dev);
311 	/* fake POS and slot for a motherboard */
312 	mca_dev->pos_id = MCA_MOTHERBOARD_POS;
313 	mca_dev->slot = MCA_MOTHERBOARD;
314 	mca_register_device(MCA_PRIMARY_BUS, mca_dev);
315 
316 	mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
317 	if (unlikely(!mca_dev))
318 		goto out_unlock_nomem;
319 
320 	/* Put motherboard into video setup mode, read integrated video
321 	 * POS registers, and turn motherboard setup off.
322 	 */
323 
324 	mca_dev->pos_register = 0xdf;
325 	outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
326 	mca_dev->name[0] = 0;
327 	mca_read_and_store_pos(mca_dev->pos);
328 	mca_configure_adapter_status(mca_dev);
329 	/* fake POS and slot for the integrated video */
330 	mca_dev->pos_id = MCA_INTEGVIDEO_POS;
331 	mca_dev->slot = MCA_INTEGVIDEO;
332 	mca_register_device(MCA_PRIMARY_BUS, mca_dev);
333 
334 	/*
335 	 * Put motherboard into scsi setup mode, read integrated scsi
336 	 * POS registers, and turn motherboard setup off.
337 	 *
338 	 * It seems there are two possible SCSI registers. Martin says that
339 	 * for the 56,57, 0xf7 is the one, but fails on the 76.
340 	 * Alfredo (apena@vnet.ibm.com) says
341 	 * 0xfd works on his machine. We'll try both of them. I figure it's
342 	 * a good bet that only one could be valid at a time. This could
343 	 * screw up though if one is used for something else on the other
344 	 * machine.
345 	 */
346 
347 	for (i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) {
348 		outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG);
349 		if (mca_read_and_store_pos(pos))
350 			break;
351 	}
352 	if (which_scsi) {
353 		/* found a scsi card */
354 		mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
355 		if (unlikely(!mca_dev))
356 			goto out_unlock_nomem;
357 
358 		for (j = 0; j < 8; j++)
359 			mca_dev->pos[j] = pos[j];
360 
361 		mca_configure_adapter_status(mca_dev);
362 		/* fake POS and slot for integrated SCSI controller */
363 		mca_dev->pos_id = MCA_INTEGSCSI_POS;
364 		mca_dev->slot = MCA_INTEGSCSI;
365 		mca_dev->pos_register = which_scsi;
366 		mca_register_device(MCA_PRIMARY_BUS, mca_dev);
367 	}
368 
369 	/* Turn off motherboard setup */
370 
371 	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
372 
373 	/*
374 	 * Now loop over MCA slots: put each adapter into setup mode, and
375 	 * read its POS registers. Then put adapter setup off.
376 	 */
377 
378 	for (i = 0; i < MCA_MAX_SLOT_NR; i++) {
379 		outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
380 		if (!mca_read_and_store_pos(pos))
381 			continue;
382 
383 		mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
384 		if (unlikely(!mca_dev))
385 			goto out_unlock_nomem;
386 
387 		for (j = 0; j < 8; j++)
388 			mca_dev->pos[j] = pos[j];
389 
390 		mca_dev->driver_loaded = 0;
391 		mca_dev->slot = i;
392 		mca_dev->pos_register = 0;
393 		mca_configure_adapter_status(mca_dev);
394 		mca_register_device(MCA_PRIMARY_BUS, mca_dev);
395 	}
396 	outb_p(0, MCA_ADAPTER_SETUP_REG);
397 
398 	/* Enable interrupts and return memory start */
399 	spin_unlock_irq(&mca_lock);
400 
401 	for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
402 		request_resource(&ioport_resource, mca_standard_resources + i);
403 
404 	mca_do_proc_init();
405 
406 	return 0;
407 
408  out_unlock_nomem:
409 	spin_unlock_irq(&mca_lock);
410  out_nomem:
411 	printk(KERN_EMERG "Failed memory allocation in MCA setup!\n");
412 	return -ENOMEM;
413 }
414 
415 subsys_initcall(mca_init);
416 
417 /*--------------------------------------------------------------------*/
418 
419 static __kprobes void
mca_handle_nmi_device(struct mca_device * mca_dev,int check_flag)420 mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
421 {
422 	int slot = mca_dev->slot;
423 
424 	if (slot == MCA_INTEGSCSI) {
425 		printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
426 			mca_dev->name);
427 	} else if (slot == MCA_INTEGVIDEO) {
428 		printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
429 			mca_dev->name);
430 	} else if (slot == MCA_MOTHERBOARD) {
431 		printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
432 			mca_dev->name);
433 	}
434 
435 	/* More info available in POS 6 and 7? */
436 
437 	if (check_flag) {
438 		unsigned char pos6, pos7;
439 
440 		pos6 = mca_device_read_pos(mca_dev, 6);
441 		pos7 = mca_device_read_pos(mca_dev, 7);
442 
443 		printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
444 	}
445 
446 } /* mca_handle_nmi_slot */
447 
448 /*--------------------------------------------------------------------*/
449 
mca_handle_nmi_callback(struct device * dev,void * data)450 static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data)
451 {
452 	struct mca_device *mca_dev = to_mca_device(dev);
453 	unsigned char pos5;
454 
455 	pos5 = mca_device_read_pos(mca_dev, 5);
456 
457 	if (!(pos5 & 0x80)) {
458 		/*
459 		 *  Bit 7 of POS 5 is reset when this adapter has a hardware
460 		 * error. Bit 7 it reset if there's error information
461 		 * available in POS 6 and 7.
462 		 */
463 		mca_handle_nmi_device(mca_dev, !(pos5 & 0x40));
464 		return 1;
465 	}
466 	return 0;
467 }
468 
mca_handle_nmi(void)469 void __kprobes mca_handle_nmi(void)
470 {
471 	/*
472 	 *  First try - scan the various adapters and see if a specific
473 	 * adapter was responsible for the error.
474 	 */
475 	bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
476 }
477