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