dpt_pci.c revision 32801
1/*
2 *       Copyright (c) 1997 by Simon Shapiro
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
31/*
32 *  dptpci.c:  Pseudo device drivers for DPT on PCI on FreeBSD
33 *
34 *  caveats:   We may need an eisa and an isa files too
35 */
36
37#ident "$Id: dpt_pci.c,v 1.10 1998/01/21 04:38:47 ShimonR Exp $"
38
39#include "opt_dpt.h"
40#include <pci.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 <pci/pcireg.h>
54#include <sys/queue.h>
55#include <pci/pcivar.h>
56
57#include <sys/dpt.h>
58#include <pci/dpt_pci.h>
59
60#include <machine/clock.h>
61
62#include <vm/vm.h>
63#include <vm/vm_param.h>
64#include <vm/pmap.h>
65
66#define PCI_BASEADR0  PCI_MAP_REG_START  /* I/O Address */
67#define PCI_BASEADR1  PCI_MAP_REG_START + 4  /* Mem I/O Address */
68
69#define ISA_PRIMARY_WD_ADDRESS    0x1f8
70
71/* Global variables */
72
73int dpt_controllers_present = 0;
74
75/* Function Prototypes */
76
77char    *dpt_pci_probe(pcici_t tag, pcidi_t type);
78void     dpt_pci_attach(pcici_t config_id, int unit);
79int      dpt_pci_shutdown(int foo, int bar);
80
81extern struct cdevsw dpt_cdevsw;
82
83static  struct pci_device dpt_pci_driver =
84{
85    "dpt",
86    dpt_pci_probe,
87    dpt_pci_attach,
88    &dpt_unit,
89    dpt_pci_shutdown
90};
91
92DATA_SET(pcidevice_set, dpt_pci_driver);
93
94/*
95 * Probe the PCI device.
96 * Some of this work will have to be duplicated in _attach
97 * because we do not know for sure how the two relate.
98 */
99
100char   *
101dpt_pci_probe(pcici_t tag, pcidi_t type)
102{
103    static char silly_message[64];
104    static int  already_announced = 0;
105
106    u_int32_t  dpt_id;
107    u_int32_t command;
108    u_int32_t class;
109
110#define pci_device  tag.cfg2.port
111#define pci_bus     tag.cfg2.forward
112#define pci_index   tag.cfg2.enable
113
114#ifndef PCI_COMMAND_MASTER_ENABLE
115#define PCI_COMMAND_MASTER_ENABLE 0x00000004
116#endif
117
118#ifndef PCI_SUBCLASS_MASS_STORAGE_SCSI
119#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00000000
120#endif
121
122    if ( !already_announced ) {
123	printf("DPT:  PCI SCSI HBA Driver, version %d.%d.%d\n",
124	       DPT_RELEASE, DPT_VERSION, DPT_PATCH);
125	++already_announced;
126    }
127
128    if ((dpt_id = (type & 0xffff0000) >> 16) == DPT_DEVICE_ID) {
129	/* This one appears to belong to us, but what is it? */
130	class = pci_conf_read(tag, PCI_CLASS_REG);
131	if (((class & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE) &&
132	    ((class & PCI_SUBCLASS_MASK) == PCI_SUBCLASS_MASS_STORAGE_SCSI) ) {
133	    /* It is a SCSI storage device.  How do talk to it? */
134	    command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
135#ifdef DPT_ALLOW_MEMIO
136	    if ( ((command & PCI_COMMAND_IO_ENABLE) == 0)
137		 && ((command & PCI_COMMAND_MEM_ENABLE) == 0) )
138#else
139	    if ( ((command & PCI_COMMAND_IO_ENABLE) == 0) )
140#endif /* DPT_ALLOW_MEMIO */
141		{
142		    printf("DPT:  Cannot map the controller registers :-(\n");
143		    return(NULL);
144		}
145	} else {
146	    printf("DPT:  Device is not Mass Storage, nor SCSI controller\n");
147	    return(NULL);
148	}
149
150	command = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
151	if ( (command & PCI_COMMAND_MASTER_ENABLE) == 0 ) {
152	    printf("DPT:  Cannot be functional without BUSMASTER. :-(\n");
153	    return (NULL);
154	}
155
156#ifdef DPT_DEBUG_PCI
157	printf("DPT:  Controller is %s mapable\n",
158	       (command & PCI_COMMAND_MEM_ENABLE)
159	       ? "MEMORY"
160	       : ((command & PCI_COMMAND_IO_ENABLE)
161		  ? "I/O"
162		  : "NOT"));
163#endif
164	return ("DPT Caching SCSI RAID Controller");
165    }
166
167#if defined(DPT_DEBUG_PCI) && defined(DPT_DEBUG_WARN)
168    printf("DPT:  Unknown Controller Type %x Found\n", dpt_id);
169    printf("     (class = %x, command = %x\n", class, command);
170#endif
171    return (NULL);
172}
173
174void
175dpt_pci_attach(pcici_t config_id, int unit)
176{
177    int          ospl;
178    int          result;
179    int          ndx;
180
181    vm_offset_t  vaddr;
182    vm_offset_t  paddr;
183    u_int16_t    io_base;
184    u_int32_t    command;
185    u_int32_t    data;
186    dpt_conf_t  *config;
187    dpt_softc_t *dpt;
188
189    if (dpt_controllers_present >= DPT_MAX_ADAPTERS) {
190	  printf("dpt%d: More than %d Adapters found!  Adapter rejected\n",
191			 unit, DPT_MAX_ADAPTERS);
192	  return;
193    }
194
195    if ((dpt = (dpt_softc_t *) malloc(sizeof(dpt_softc_t), M_DEVBUF, M_NOWAIT))
196		== NULL) {
197	  printf("dpt%d: Failed to allocate %d bytes for a DPT softc\n",
198			 unit, sizeof(dpt_softc_t));
199	  return;
200    }
201
202    /*
203     * Initialize the queues.  See dpt.h for details. We do this here,
204     * as we may get hit with interrupts at any moment and we want to
205     * have a minimal structure in place to handle them. We also want to
206     * register interrupts correctly. To do so, we need a valid dpt
207     * structure. To have that, we need this  minimal setup here.
208     */
209    bzero(dpt, sizeof(dpt_softc_t));
210
211    TAILQ_INIT(&dpt->free_ccbs);
212    TAILQ_INIT(&dpt->waiting_ccbs);
213    TAILQ_INIT(&dpt->submitted_ccbs);
214    TAILQ_INIT(&dpt->completed_ccbs);
215
216    if (TAILQ_EMPTY(&dpt_softc_list)) {
217	  TAILQ_INIT(&dpt_softc_list);
218    }
219
220    TAILQ_INSERT_TAIL(&dpt_softc_list, dpt, links);
221    dpt->queue_status       = DPT_QUEUES_NONE_ACTIVE;
222    dpt->commands_processed = 0;
223
224#ifdef DPT_MEASURE_PERFORMANCE
225    /* Zero out all command counters */
226    bzero((void *)&dpt->performance, sizeof(dpt_perf_t));
227    for ( ndx = 0; ndx < 256; ndx ++ )
228	  dpt->performance.min_command_time[ndx] = BIG_ENOUGH;
229
230    dpt->performance.min_intr_time     = BIG_ENOUGH;
231    dpt->performance.min_waiting_time  = BIG_ENOUGH;
232    dpt->performance.min_submit_time   = BIG_ENOUGH;
233    dpt->performance.min_complete_time = BIG_ENOUGH;
234    dpt->performance.min_eata_tries    = BIG_ENOUGH;
235
236    for (ndx = 0; ndx < 10; ndx++ ) {
237	    dpt->performance.read_by_size_min_time[ndx] = BIG_ENOUGH;
238	    dpt->performance.write_by_size_min_time[ndx] = BIG_ENOUGH;
239    }
240#endif        /* DPT_MEASURE_PERFORMANCE */
241
242    dpt->unit = unit;
243    dpt->handle_interrupts = 0;  /*
244								  * Do not set to 1 until all
245								  * initialization is done
246								  */
247    dpt->v_membase = NULL;
248    dpt->p_membase = NULL;
249    io_base = 0;
250    vaddr   = 0;
251    paddr   = 0;
252    command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
253
254#ifdef DPT_ALLOW_MEMIO
255    if ( (command & PCI_COMMAND_MEM_ENABLE) == 0 ) {
256#ifdef DPT_DEBUG_PCI
257	  printf("dpt%d: Cannot be memory mapped\n", unit);
258#endif
259	force_io:
260	  if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) {
261	    printf("dpt%d: Cannot be I/O mapped either :-(\n", unit);
262	    free(dpt, M_DEVBUF);
263	    return;
264	  } else {
265	    data = pci_conf_read(config_id, PCI_MAP_REG_START);
266	    if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) {
267#ifdef DPT_DEBUG_ERROR
268		  printf("dpt%d: Failed to map as I/O :-(\n", unit);
269#endif
270		  free(dpt, M_DEVBUF);
271		  return;
272	    } else {
273		  dpt->io_base = io_base + 0x10;
274#ifdef DPT_DEBUG_PCI
275		  printf("dpt%d: Mapped registers to I/O space, "
276				 "starting at %x\n",
277				 dpt->unit, dpt->io_base);
278#endif
279	    }
280	  }
281    } else {
282	  if ( pci_map_mem(config_id, PCI_MAP_REG_START + 4, &vaddr,
283					   &paddr) == 0 ) {
284#ifdef DPT_DEBUG_ERROR
285	    printf("dpt%d: Failed to map as MEMORY.\n"
286			   "  Attemting to force I/O mapping\n", unit);
287#endif
288	    goto force_io;
289	  } else {
290	    dpt->v_membase = (volatile u_int8_t *)(vaddr + 0x10);
291	    dpt->p_membase = (volatile u_int8_t *)(paddr + 0x10);
292#ifdef DPT_DEBUG_PCI
293	    printf("dpt%d: Mapped registers to MEMORY space, "
294			   "starting at %x/%x\n",
295			   dpt->unit, dpt->v_membase, dpt->p_membase);
296#endif
297	  }
298    }
299
300#else /* !DPT_ALLOW_MEMIO */
301    data = pci_conf_read(config_id, PCI_MAP_REG_START);
302    if ((command & PCI_COMMAND_IO_ENABLE) == 0 ) {
303	  printf("dpt%d: Registers cannot be I/O mapped :-(\n", unit);
304	  free(dpt, M_DEVBUF);
305	  return;
306    } else {
307	  if ( pci_map_port(config_id, PCI_MAP_REG_START, &io_base) == 0 ) {
308#ifdef DPT_DEBUG_ERROR
309	    printf("dpt%d: Failed to map registers as I/O :-(\n", unit);
310#endif
311	    free(dpt, M_DEVBUF);
312	    return;
313	  } else {
314	    dpt->io_base = io_base + 0x10;
315#ifdef DPT_DEBUG_PCI
316	    printf("dpt%d: Mapped registers to I/O space, starting at %x\n",
317			   dpt->unit, dpt->io_base);
318#endif
319	  }
320    }
321#endif /* !DPT_ALLOW_MEMIO */
322
323    if (pci_map_int(config_id, dpt_intr, (void *)dpt, &cam_imask) == 0) {
324#ifdef DPT_DEBUG_WARN
325	  printf("dpt%d: Failed to map interrupt :-(\n", unit);
326#endif
327	  free(dpt, M_DEVBUF);
328	  return;
329    }
330
331    /* If the DPT is mapped as an IDE controller, let it be IDE controller */
332    if (io_base == (ISA_PRIMARY_WD_ADDRESS)) {
333#ifdef DPT_DEBUG_WARN
334	  printf("dpt%d: Mapped as an IDE controller.  "
335			 "Disabling SCSI setup\n", unit);
336#endif
337	  free(dpt, M_DEVBUF);
338	  return;
339    } else {
340	  if ((config = dpt_get_conf(dpt, 0xc1, 7,
341								 sizeof(dpt_conf_t), 1)) == NULL) {
342#ifdef DPT_DEBUG_ERROR
343	    printf("dpt%d: Failed to get board configuration (%x)\n",
344			   unit, BaseRegister(dpt));
345#endif
346	    free(dpt, M_DEVBUF);
347	    return;
348	  }
349    }
350
351    dpt->max_id      = config->MAX_ID;
352    dpt->max_lun     = config->MAX_LUN;
353    dpt->irq         = config->IRQ;
354    dpt->channels    = config->MAX_CHAN;
355    dpt->dma_channel = (8 - config->DMA_channel) & 7;
356
357#ifdef DPT_DEBUG_SETUP
358    printf("dpt%d: max_id = %d, max_chan = %d, max_lun = %d\n",
359		   dpt->unit, dpt->max_id, dpt->channels, dpt->max_lun);
360#endif
361
362    if (result = dpt_setup(dpt, config)) {
363	  free(config, M_TEMP);
364	  free(dpt, M_DEVBUF);
365	  printf("dpt%d: dpt_setup failed (%d).  Driver Disabled :-(\n",
366			 dpt->unit, result);
367    } else {
368	  /* clean up the informational data, and display */
369	  char clean_vendor[9];
370	  char clean_model[17];
371	  char clean_firmware[5];
372	  char clean_protocol[5];
373	  char clean_other[7];
374
375	  int     ndx;
376
377	  strncpy(clean_other, dpt->board_data.otherData, 8);
378	  clean_other[6] = '\0';
379	  for (ndx = 5; ndx >= 0; ndx--) {
380	    if (clean_other[ndx] == ' ')
381		  clean_other[ndx] = '\0';
382	    else
383		  break;
384	  }
385	  strncpy(dpt->board_data.otherData, clean_other, 6);
386
387	  strncpy(clean_vendor, dpt->board_data.vendor, 8);
388	  clean_vendor[8] = '\0';
389	  for (ndx = 7; ndx >= 0; ndx--) {
390	    if (clean_vendor[ndx] == ' ')
391		  clean_vendor[ndx] = '\0';
392	    else
393		  break;
394	  }
395	  strncpy(dpt->board_data.vendor, clean_vendor, 8);
396
397	  strncpy(clean_model, dpt->board_data.modelNum, 16);
398	  clean_model[16] = '\0';
399	  for (ndx = 15; ndx >= 0; ndx--) {
400	    if (clean_model[ndx] == ' ')
401		  clean_model[ndx] = '\0';
402	    else
403		  break;
404	  }
405	  strncpy(dpt->board_data.modelNum, clean_model, 16);
406
407	  strncpy(clean_firmware, dpt->board_data.firmware, 4);
408	  clean_firmware[4] = '\0';
409	  for (ndx = 3; ndx >= 0; ndx--) {
410	    if (clean_firmware[ndx] == ' ')
411		  clean_firmware[ndx] = '\0';
412	    else
413		  break;
414	  }
415	  strncpy(dpt->board_data.firmware, clean_firmware, 4);
416
417	  strncpy(clean_protocol, dpt->board_data.protocol, 4);
418	  clean_protocol[4] = '\0';
419	  for (ndx = 3; ndx >= 0; ndx--) {
420	    if (clean_protocol[ndx] == ' ')
421		  clean_protocol[ndx] = '\0';
422	    else
423		  break;
424	  }
425	  strncpy(dpt->board_data.protocol, clean_protocol, 4);
426
427	  dpt_detect_cache(dpt);
428
429	  printf("dpt%d: %s type %x, model %s firmware %s, Protocol %s \n"
430			 "      on port %x with %s cache.  LED = %s\n",
431			 dpt->unit, clean_vendor, dpt->board_data.deviceType,
432			 clean_model, clean_firmware, clean_protocol, dpt->io_base,
433			 (dpt->cache_type == DPT_NO_CACHE)
434			 ? "Disabled"
435			 : (dpt->cache_type == DPT_CACHE_WRITETHROUGH)
436			 ? "Write-Through"
437			 : "Write-Back",
438			 i2bin(dpt_blinking_led(dpt), 8));
439	  printf("dpt%d: Enabled Options:\n", dpt->unit);
440#ifdef DPT_LOST_IRQ
441	  printf("      Recover Lost Interrupts\n");
442#endif
443#ifdef DPT_VERIFY_HINTR
444	  printf("      Verify Lost Transactions\n");
445#endif
446#ifdef DPT_RESTRICTED_FREELIST
447	  printf("      Restrict the Freelist Size\n");
448#endif
449#ifdef DPT_MEASURE_PERFORMANCE
450	  printf("      Collect Metrics\n");
451#endif
452#ifdef DPT_FREELIST_IS_STACK
453	  printf("      Optimize CPU Cache\n");
454#endif
455#ifdef DPT_HANDLE_TIMEOUTS
456	  printf("      Handle Timeouts\n");
457#endif
458#ifdef DPT_ALLOW_MEMIO
459	  printf("      Allow I/O to be Memeory Mapped\n");
460#endif
461#ifdef DPT_HINTR_CHECK_SOFTC
462	  printf("      Validate SoftC at Interrupt\n");
463#endif
464
465	  /* register shutdown handlers */
466	  result = at_shutdown((bootlist_fn)dpt_shutdown, (void *)dpt,
467						   SHUTDOWN_POST_SYNC);
468	  switch ( result ) {
469	  case 0:
470#ifdef DPT_DEBUG_SHUTDOWN
471		printf("dpt%d: Shutdown handler registered\n", dpt->unit);
472#endif
473		break;
474	  default:
475#ifdef DPT_DEBUG_WARN
476		printf("dpt%d: Failed to register shutdown handler (%d)\n",
477			   dpt->unit, result);
478#endif
479		break;
480	  }
481
482	  /* Attach SCSI devices */
483	  dpt_attach(dpt);
484	  ++dpt_controllers_present;
485
486	  /*
487	   * Now we create the DEVFS entry.
488	   * This would be normally done from dpt_control.c,
489	   * But since it appears to be called before we do here,
490	   * We never get the entries made.
491       */
492#ifdef DEVFS
493	  dpt->devfs_data_token = devfs_add_devswf(&dpt_cdevsw, dpt->unit, DV_CHR,
494											   UID_ROOT, GID_WHEEL, 0600,
495											   "dpt%d", dpt->unit);
496	  dpt->devfs_ctl_token = devfs_add_devswf(&dpt_cdevsw,
497											  dpt->unit | SCSI_CONTROL_MASK,
498											  DV_CHR,
499											  UID_ROOT, GID_WHEEL, 0600,
500											  "dpt%d.ctl", dpt->unit);
501#endif
502    }
503}
504
505int
506dpt_pci_shutdown(int foo, int bar)
507{
508#ifdef DPT_DEBUG_WARN
509    printf("dpt_pci_shutdown(%x, %x)\n", foo, bar);
510#endif
511    return (0);
512}
513
514/* End of the DPT PCI part of the driver */
515
516/*
517 * Hello emacs, these are the
518 * Local Variables:
519 *  c-indent-level:               8
520 *  c-continued-statement-offset: 8
521 *  c-continued-brace-offset:     0
522 *  c-brace-offset:              -8
523 *  c-brace-imaginary-offset:     0
524 *  c-argdecl-indent:             8
525 *  c-label-offset:              -8
526 *  c++-hanging-braces:           1
527 *  c++-access-specifier-offset: -8
528 *  c++-empty-arglist-indent:     8
529 *  c++-friend-offset:            0
530 * End:
531 */
532