dpt_eisa.c revision 36129
1/**
2 *       Copyright (c) 1997 by Matthew N. Dodd <winter@jurai.net>
3 *       All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/* Credits:  Based on and part of the DPT driver for FreeBSD written and
31 *           maintained by Simon Shapiro <shimon@simon-shapiro.org>
32 */
33
34/*
35 * $Id: dpt_eisa.c,v 1.1 1998/03/11 00:30:12 julian Exp $
36 */
37
38#include "eisa.h"
39#if NEISA > 0
40#include "opt_dpt.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/malloc.h>
45#include <sys/buf.h>
46#include <sys/proc.h>
47#include <sys/kernel.h>
48
49#include <scsi/scsi_all.h>
50#include <scsi/scsi_message.h>
51#include <scsi/scsiconf.h>
52
53#include <i386/eisa/eisaconf.h>
54
55#include <sys/dpt.h>
56#include <i386/eisa/dpt_eisa.h>
57
58#include <machine/clock.h>
59
60#include <vm/vm.h>
61#include <vm/vm_param.h>
62#include <vm/pmap.h>
63
64/* Function Prototypes */
65
66int		dpt_eisa_probe(void);
67int		dpt_eisa_attach(struct eisa_device*);
68int		dpt_eisa_shutdown(int);
69
70static const char	*dpt_eisa_match(eisa_id_t);
71
72static struct eisa_driver dpt_eisa_driver =
73{
74	"dpt",
75	dpt_eisa_probe,
76	dpt_eisa_attach,
77	dpt_eisa_shutdown,
78	&dpt_unit
79};
80
81DATA_SET (eisadriver_set, dpt_eisa_driver);
82
83int
84dpt_eisa_probe(void)
85{
86	static int		already_announced = 0;
87	u_int32_t		io_base;
88	u_int32_t		irq;
89	struct eisa_device	*e_dev = NULL;
90	dpt_conf_t		*config;
91	dpt_softc_t		*dpt;
92        int			count = 0;
93
94	if ( !already_announced ) {
95		printf("DPT:  EISA SCSI HBA Driver, version %d.%d.%d\n",
96			DPT_RELEASE, DPT_VERSION, DPT_PATCH);
97		++already_announced;
98	}
99
100	if ((dpt = (dpt_softc_t *) malloc(sizeof(dpt_softc_t),
101					  M_DEVBUF, M_NOWAIT)) == NULL) {
102		printf("dpt_eisa_probe() : Failed to allocate %d bytes for a DPT softc\n", sizeof(dpt_softc_t));
103		return -1;
104	}
105
106	bzero(dpt, sizeof(dpt_softc_t));
107
108	TAILQ_INIT(&dpt->free_ccbs);
109	TAILQ_INIT(&dpt->waiting_ccbs);
110	TAILQ_INIT(&dpt->submitted_ccbs);
111	TAILQ_INIT(&dpt->completed_ccbs);
112
113	dpt->queue_status = DPT_QUEUES_NONE_ACTIVE;
114	dpt->commands_processed = 0;
115	dpt->handle_interrupts = 0;
116	dpt->v_membase = NULL;
117	dpt->p_membase = NULL;
118
119	dpt->unit = -1;
120
121	while ((e_dev = eisa_match_dev(e_dev, dpt_eisa_match))) {
122		io_base = (e_dev->ioconf.slot * EISA_SLOT_SIZE)
123			 + DPT_EISA_SLOT_OFFSET;
124
125		eisa_add_iospace(e_dev, io_base,
126				 DPT_EISA_IOSIZE, RESVADDR_NONE);
127
128		dpt->io_base = io_base;
129
130		if ((config = dpt_get_conf(dpt, 0xc1, 7,
131				      sizeof(dpt_conf_t), 1)) == NULL) {
132#ifdef DPT_DEBUG_ERROR
133			printf("eisa0:%d dpt_eisa_probe() : Failed to get board configuration.\n",
134				e_dev->ioconf.slot);
135#endif
136			continue;
137		}
138
139		irq = config->IRQ;
140
141		eisa_add_intr(e_dev, irq);
142		eisa_registerdev(e_dev, &dpt_eisa_driver);
143
144		count++;
145
146	}
147
148	free(dpt, M_DEVBUF);
149	return count;
150}
151
152int
153dpt_eisa_attach(e_dev)
154	struct eisa_device	*e_dev;
155{
156	int		result;
157	int		ndx;
158
159	dpt_conf_t	*config;
160	dpt_softc_t	*dpt;
161
162        int		unit = e_dev->unit;
163        int		irq;
164	resvaddr_t	*io_space;
165
166	if (TAILQ_FIRST(&e_dev->ioconf.irqs) == NULL) {
167#ifdef DPT_DEBUG_ERROR
168		printf("dpt%d: Can't retrieve irq from EISA config struct.\n",
169			unit);
170#endif
171		return -1;
172	}
173
174	irq = TAILQ_FIRST(&e_dev->ioconf.irqs)->irq_no;
175	io_space = e_dev->ioconf.ioaddrs.lh_first;
176
177	if (!io_space) {
178#ifdef DPT_DEBUG_ERROR
179		printf("dpt%d: No I/O space?!\n", unit);
180#endif
181		return -1;
182	}
183
184	if ( dpt_controllers_present >= DPT_MAX_ADAPTERS ){
185		printf("dpt%d: More than %d Adapters found!  Adapter rejected\n",
186			unit, DPT_MAX_ADAPTERS);
187		return -1;
188	}
189
190	if ((dpt = (dpt_softc_t *) malloc(sizeof(dpt_softc_t),
191					  M_DEVBUF, M_NOWAIT)) == NULL) {
192		printf("dpt%d: Failed to allocate %d bytes for a DPT softc\n",
193			unit, sizeof(dpt_softc_t));
194		return -1;
195	}
196
197	/*
198	 * Initialize the queues.  See dpt.h for details. We do this here,
199	 * as we may get hit with interrupts at any moment and we want to
200	 * have a minimal structure in place to handle them. We also want to
201	 * register interrupts correctly. To do so, we need a valid dpt
202	 * structure. To have that, we need this  minimal setup here.
203	 */
204
205	bzero(dpt, sizeof(dpt_softc_t));
206
207	TAILQ_INIT(&dpt->free_ccbs);
208	TAILQ_INIT(&dpt->waiting_ccbs);
209	TAILQ_INIT(&dpt->submitted_ccbs);
210	TAILQ_INIT(&dpt->completed_ccbs);
211
212	if (TAILQ_EMPTY(&dpt_softc_list)) {
213		TAILQ_INIT(&dpt_softc_list);
214	}
215
216	TAILQ_INSERT_TAIL(&dpt_softc_list, dpt, links);
217	dpt->queue_status       = DPT_QUEUES_NONE_ACTIVE;
218	dpt->commands_processed = 0;
219
220#ifdef DPT_MEASURE_PERFORMANCE
221	/* Zero out all command counters */
222	bzero((void *)&dpt->performance, sizeof(dpt_perf_t));
223#endif		/* DPT_MEASURE_PERFORMANCE */
224
225	dpt->handle_interrupts = 0;	/*
226					 * Do not set to 1 until all
227					 * initialization is done
228					 */
229	dpt->v_membase = NULL;
230	dpt->p_membase = NULL;
231
232	dpt->unit = unit;
233	dpt->io_base = (e_dev->ioconf.slot * EISA_SLOT_SIZE)
234			 + DPT_EISA_SLOT_OFFSET;
235
236	eisa_reg_start(e_dev);
237
238	if (eisa_reg_iospace(e_dev, io_space)) {
239#ifdef DPT_DEBUG_ERROR
240		printf("dpt%d: eisa_reg_iospace() failed.\n", unit);
241#endif
242		free(dpt, M_DEVBUF);
243		return -1;
244	}
245
246	/* reset the card? */
247
248	/* If the DPT is mapped as an IDE controller, let it be IDE controller */
249	if (dpt->io_base == ISA_PRIMARY_WD_ADDRESS) {
250#ifdef DPT_DEBUG_WARN
251		printf("dpt%d: Mapped as an IDE controller.  "
252			"Disabling SCSI setup\n", unit);
253#endif
254		free(dpt, M_DEVBUF);
255		return -1;
256	} else {
257		if ((config = dpt_get_conf(dpt, 0xc1, 7,
258					   sizeof(dpt_conf_t), 1)) == NULL) {
259#ifdef DPT_DEBUG_ERROR
260			printf("dpt%d: Failed to get board configuration (%x)\n",
261				 unit, BaseRegister(dpt));
262#endif
263			free(dpt, M_DEVBUF);
264			return -1;
265		}
266	}
267
268	if(eisa_reg_intr(e_dev, irq, dpt_intr, (void *)dpt, &cam_imask,
269			/* shared == */ config->IRQ_TR)) {
270#ifdef DPT_DEBUG_ERROR
271		printf("dpt%d: eisa_reg_intr() failed.\n", unit);
272#endif
273		free(dpt, M_DEVBUF);
274		return -1;
275	}
276	eisa_reg_end(e_dev);
277
278	/* Enable our interrupt handler. */
279	if (eisa_enable_intr(e_dev, irq)) {
280#ifdef DPT_DEBUG_ERROR
281		printf("dpt%d: eisa_enable_intr() failed.\n", unit);
282#endif
283		free(dpt, M_DEVBUF);
284		eisa_release_intr(e_dev, irq, dpt_intr);
285		return -1;
286	}
287
288	dpt->max_id      = config->MAX_ID;
289	dpt->max_lun     = config->MAX_LUN;
290	dpt->irq         = config->IRQ;
291	dpt->channels    = config->MAX_CHAN;
292	dpt->dma_channel = (8 - config->DMA_channel) & 7;
293
294#ifdef DPT_DEBUG_SETUP
295	printf("dpt%d: max_id = %d, max_chan = %d, max_lun = %d\n",
296		dpt->unit, dpt->max_id, dpt->channels, dpt->max_lun);
297#endif
298
299	if (result = dpt_setup(dpt, config)) {
300		free(config, M_TEMP);
301		free(dpt, M_DEVBUF);
302		printf("dpt%d: dpt_setup failed (%d).  Driver Disabled :-(\n",
303		dpt->unit, result);
304	} else {
305		/* clean up the informational data, and display */
306		char clean_vendor[9];
307		char clean_model[17];
308		char clean_firmware[5];
309		char clean_protocol[5];
310		char clean_other[7];
311
312		int     ndx;
313
314		strncpy(clean_other, dpt->board_data.otherData, 8);
315		clean_other[6] = '\0';
316		for (ndx = 5; ndx >= 0; ndx--) {
317			if (clean_other[ndx] == ' ') {
318				clean_other[ndx] = '\0';
319			} else {
320				break;
321			}
322		}
323
324		strncpy(dpt->board_data.otherData, clean_other, 6);
325
326		strncpy(clean_vendor, dpt->board_data.vendor, 8);
327		clean_vendor[8] = '\0';
328
329		for (ndx = 7; ndx >= 0; ndx--) {
330			if (clean_vendor[ndx] == ' ') {
331				clean_vendor[ndx] = '\0';
332			} else {
333				break;
334			}
335		}
336
337		strncpy(dpt->board_data.vendor, clean_vendor, 8);
338
339		strncpy(clean_model, dpt->board_data.modelNum, 16);
340		clean_model[16] = '\0';
341
342		for (ndx = 15; ndx >= 0; ndx--) {
343			if (clean_model[ndx] == ' ') {
344				clean_model[ndx] = '\0';
345			} else {
346				break;
347			}
348		}
349
350		strncpy(dpt->board_data.modelNum, clean_model, 16);
351
352		strncpy(clean_firmware, dpt->board_data.firmware, 4);
353		clean_firmware[4] = '\0';
354
355		for (ndx = 3; ndx >= 0; ndx--) {
356			if (clean_firmware[ndx] == ' ')
357				clean_firmware[ndx] = '\0';
358			else
359				break;
360		}
361
362		strncpy(dpt->board_data.firmware, clean_firmware, 4);
363
364		strncpy(clean_protocol, dpt->board_data.protocol, 4);
365		clean_protocol[4] = '\0';
366
367		for (ndx = 3; ndx >= 0; ndx--) {
368			if (clean_protocol[ndx] == ' ')
369				clean_protocol[ndx] = '\0';
370			else
371				break;
372		}
373
374		strncpy(dpt->board_data.protocol, clean_protocol, 4);
375
376		dpt_detect_cache(dpt);
377
378		printf("dpt%d: %s type %x, model %s firmware %s, Protocol %s \n"
379			"      on port %x with %dMB %s cache.  LED = %s\n",
380			dpt->unit, clean_vendor, dpt->board_data.deviceType,
381			clean_model, clean_firmware, clean_protocol, dpt->io_base,
382			dpt->cache_size,
383			(dpt->cache_type == DPT_NO_CACHE)
384			? "Disabled"
385			: (dpt->cache_type == DPT_CACHE_WRITETHROUGH)
386			? "Write-Through"
387			: "Write-Back",
388			i2bin(dpt_blinking_led(dpt), 8));
389
390		printf("dpt%d: Enabled Options:\n", dpt->unit);
391
392#ifdef DPT_VERIFY_HINTR
393		printf("      Verify Lost Transactions\n");
394#endif
395#ifdef DPT_RESTRICTED_FREELIST
396		printf("      Restrict the Freelist Size\n");
397#endif
398#ifdef DPT_TRACK_CCB_STATES
399		printf("      Precisely Track State Transitions\n");
400#endif
401#ifdef DPT_MEASURE_PERFORMANCE
402		printf("      Collect Metrics\n");
403#endif
404#ifdef DPT_FREELIST_IS_STACK
405		printf("      Optimize CPU Cache\n");
406#endif
407#ifdef DPT_HANDLE_TIMEOUTS
408		printf("      Handle Timeouts\n");
409#endif
410#ifdef DPT_ALLOW_MEMIO
411		printf("      Allow I/O to be Memeory Mapped\n");
412#endif
413#ifdef DPT_HINTR_CHECK_SOFTC
414		printf("      Validate SoftC at Interrupt\n");
415#endif
416
417		/* register shutdown handlers */
418		result = at_shutdown((bootlist_fn)dpt_shutdown, (void *)dpt,
419						SHUTDOWN_POST_SYNC);
420		switch ( result ) {
421			case 0:
422#ifdef DPT_DEBUG_SHUTDOWN
423				printf("dpt%d: Shutdown handler registered\n", dpt->unit);
424#endif
425				break;
426			default:
427#ifdef DPT_DEBUG_WARN
428				printf("dpt%d: Failed to register shutdown handler (%d)\n",
429					dpt->unit, result);
430#endif
431				 break;
432		}
433
434		dpt_attach(dpt);
435	}
436
437	++dpt_controllers_present;
438
439	return 0;
440}
441
442int
443dpt_eisa_shutdown(foo)
444	int	foo;
445{
446#ifdef DPT_DEBUG_WARN
447	printf("dpt_pci_shutdown(%x)\n", foo);
448#endif
449	return (0);
450}
451
452static const char	*
453dpt_eisa_match(type)
454	eisa_id_t	type;
455{
456	switch (type) {
457		case DPT_EISA_DPT2402 :
458			return ("DPT PM2012A/9X");
459			break;
460		case DPT_EISA_DPTA401 :
461			return ("DPT PM2012B/9X");
462			break;
463		case DPT_EISA_DPTA402 :
464			return ("DPT PM2012B2/9X");
465			break;
466		case DPT_EISA_DPTA410 :
467			return ("DPT PM2x22A/9X");
468			break;
469		case DPT_EISA_DPTA411 :
470			return ("DPT Spectre");
471			break;
472		case DPT_EISA_DPTA412 :
473			return ("DPT PM2021A/9X");
474			break;
475		case DPT_EISA_DPTA420 :
476			return ("DPT Smart Cache IV (PM2042)");
477			break;
478		case DPT_EISA_DPTA501 :
479			return ("DPT PM2012B1/9X");
480			break;
481		case DPT_EISA_DPTA502 :
482			return ("DPT PM2012Bx/9X");
483			break;
484		case DPT_EISA_DPTA701 :
485			return ("DPT PM2011B1/9X");
486			break;
487		case DPT_EISA_DPTBC01 :
488			return ("DPT PM3011/7X ESDI");
489			break;
490		case DPT_EISA_NEC8200 :
491			return ("NEC EATA SCSI");
492			break;
493		case DPT_EISA_ATT2408 :
494			return ("ATT EATA SCSI");
495			break;
496		default:
497			break;
498	}
499
500	return (NULL);
501}
502
503#endif /* NEISA > 0 */
504