1 /*
2 ** $Id: sim_buslogic.c,v 1.8 1998/04/21 00:54:52 swetland Exp $
3 **
4 ** SCSI Interface Module for BusLogic MultiMaster Controllers
5 ** Copyright 1998, Brian J. Swetland <swetland@frotz.net>
6 **
7 ** Portions Copyright (c) 1994 by Be Incorporated.
8 ** This file may be used under the terms of the Be Sample Code License.
9 */
10
11
12 #include <BeBuild.h>
13 #include <iovec.h>
14 #include <KernelExport.h>
15
16 /*
17 ** Debug options:
18 */
19 #define DEBUG_BUSLOGIC /* Print Debugging Messages */
20 #define xDEBUG_TRANSACTIONS
21 #define xSERIALIZE_REQS /* only allow one req to the controller at a time */
22 #define xVERBOSE_IRQ /* enable kprintf()s in the IRQ handler */
23
24 #include <ByteOrder.h>
25 /*
26 ** Macros for virt <-> phys translation
27 */
28 #define PhysToVirt(n) ((void *) (((uint32) n) + bl->phys_to_virt))
29 #define VirtToPhys(n) (((uint32) n) + bl->virt_to_phys)
30
31 /*
32 ** Debugging Macros
33 */
34 #ifdef DEBUG_BUSLOGIC
35 #define d_printf dprintf
36 #ifdef DEBUG_TRANSACTIONS
37 #define dt_printf dprintf
38 #else
39 #define dt_printf(x...)
40 #endif
41 #else
42 #define d_printf(x...)
43 #endif
44
45 /* TODO:
46 **
47 ** - endian issues: the MultiMaster is little endian, should use swap()
48 ** macro for PPC compatibility whenever exchanging addresses with it (DONE)
49 ** - wrap phys addrs with ram_address()
50 ** - support scatter-gather in the ccb_scsiio struct (DONE)
51 ** - allocte bl_ccb_## semaphores on-demand (1/2 - only use 32)
52 ** - error checking for *_sem functions... we're without a net right now
53 ** - sync? (DONE - card handles this)
54 ** - tagged queuing?
55 */
56
57 #include <OS.h>
58 #include <KernelExport.h>
59 #include <PCI.h>
60 #include <CAM.h>
61
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
65
66 #include "buslogic.h"
67
68 /*
69 ** Constants for the SIM
70 */
71 #define SIM_VERSION 0x01
72 #define HBA_VERSION 0x01
73
74 static char sim_vendor_name[] = "Be, Inc.";
75 static char hba_vendor_name[] = "BusLogic";
76 static char controller_family[] = "MultiMaster PCI";
77
78 static pci_module_info *pci;
79 static cam_for_sim_module_info *cam;
80
81 static char cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
82 static char pci_name[] = B_PCI_MODULE_NAME;
83
84 /*
85 ** IO Macros
86 */
87
88 /* XXX - fix me bjs */
89 #define inb(p) (*pci->read_io_8)(p)
90 #define outb(p,v) (*pci->write_io_8)(p,v)
91
92 #ifdef __i386__
93 #define toLE(x) (x)
94 #define unLE(x) (x)
95 #else
96 #define toLE(x) B_HOST_TO_LENDIAN_INT32(x)
97 #define unLE(x) B_LENDIAN_TO_HOST_INT32(x)
98 #endif
99
100
101 static int32
scsi_int_dispatch(void * data)102 scsi_int_dispatch(void *data)
103 {
104 BusLogic *bl = (BusLogic *) data;
105 BL_CCB32 *bl_ccb;
106 uchar intstat = inb(BL_INT_REG);
107
108 #if BOOT
109 #else
110 if(!(intstat & BL_INT_INTV)) return B_UNHANDLED_INTERRUPT;
111 #endif
112 if(intstat & BL_INT_CMDC) {
113 bl->done = 1;
114 #ifdef VERBOSE_IRQ
115 kprintf("buslogic_irq: Command Complete\n");
116 #endif
117 }
118
119 if(intstat & BL_INT_RSTS){
120 kprintf("buslogic_irq: BUS RESET\n");
121 }
122
123 /* have we got mail? */
124 if(intstat & BL_INT_IMBL){
125 while(bl->in_boxes[bl->in_nextbox].completion_code){
126 bl_ccb = (BL_CCB32 *)
127 PhysToVirt(unLE(bl->in_boxes[bl->in_nextbox].ccb_phys));
128
129 #ifdef VERBOSE_IRQ
130 kprintf("buslogic_irq: CCB %08x (%08x) done, cc=0x%02x\n",
131 unLE(bl->in_boxes[bl->in_nextbox].ccb_phys), (uint32) bl_ccb,
132 bl->in_boxes[bl->in_nextbox].completion_code);
133 #endif
134 release_sem_etc(bl_ccb->done, 1, B_DO_NOT_RESCHEDULE);
135
136 bl->in_boxes[bl->in_nextbox].completion_code = 0;
137 bl->in_nextbox++;
138 if(bl->in_nextbox == bl->box_count) bl->in_nextbox = 0;
139 }
140 }
141
142 /* acknowledge the irq */
143 outb(BL_CONTROL_REG, BL_CONTROL_RINT);
144
145 return B_HANDLED_INTERRUPT;
146 }
147
148
149 /* Execute a command, with optional params send (in[in_len]) and
150 ** results received (out[out_len])
151 */
bl_execute(BusLogic * bl,uchar command,void * in,int in_len,void * out,int out_len)152 static int bl_execute(BusLogic *bl, uchar command,
153 void *in, int in_len,
154 void *out, int out_len)
155 {
156 uchar status;
157 uchar *_in, *_out;
158 #ifdef TIMEOUT
159 int timeout;
160 #endif
161
162 _in = (uchar *) in;
163 _out = (uchar *) out;
164
165 if(!(inb(BL_STATUS_REG) & BL_STATUS_HARDY)) {
166 d_printf("buslogic: command 0x%02x %d/%d, not ready\n",
167 command, in_len, out_len);
168 return 1;
169 }
170
171 outb(BL_COMMAND_REG, command);
172
173 #ifdef TIMEOUT
174 timeout = 100;
175 #endif
176 while(in_len){
177 status = inb(BL_STATUS_REG);
178 if(status & BL_STATUS_CMDINV) {
179 d_printf("buslogic: command 0x%02x %d/%d invalid\n",
180 command, in_len, out_len);
181 return 1;
182 }
183 if(status & BL_STATUS_CPRBSY) {
184 #ifdef TIMEOUT
185 timeout--;
186 if(!timeout) {
187 d_printf("buslogic: command 0x%02 timed out (a)\n",command);
188 return 1;
189 }
190 spin(100);
191 #endif
192 continue;
193 }
194 outb(BL_COMMAND_REG, *_in);
195 _in++;
196 in_len--;
197 }
198
199 #ifdef TIMEOUT
200 timeout = 100;
201 #endif
202 while(out_len){
203 status = inb(BL_STATUS_REG);
204 if(status & BL_STATUS_CMDINV) {
205 d_printf("buslogic: command 0x%02x %d/%d invalid\n",
206 command, in_len, out_len);
207 return 1;
208 }
209 if(status & BL_STATUS_DIRRDY) {
210 *_out = inb(BL_DATA_REG);
211 _out++;
212 out_len--;
213 } else {
214 #ifdef TIMEOUT
215 timeout--;
216 if(!timeout) {
217 d_printf("buslogic: command 0x%02 timed out (b)\n",command);
218 return 1;
219 }
220 spin(100);
221 #endif
222 }
223 }
224
225 #ifdef TIMEOUT
226 timeout = 100;
227 #endif
228 while(!(inb(BL_STATUS_REG) & BL_STATUS_HARDY)) {
229 #ifdef TIMEOUT
230 timeout--;
231 if(!timeout) {
232 d_printf("buslogic: command 0x%02 timed out (c)\n",command);
233 return 1;
234 }
235 spin(100);
236 #endif
237 }
238
239 return 0;
240 }
241
242 /* Initialize the BT-9X8 and confirm that it is operating as expected
243 */
init_buslogic(BusLogic * bl)244 static long init_buslogic(BusLogic *bl)
245 {
246 uchar status;
247 uchar id[16];
248 int i;
249 char *str = bl->productname;
250
251 d_printf("buslogic: init_buslogic()\n");
252
253 dprintf("buslogic: reset: ");
254 outb(BL_CONTROL_REG, BL_CONTROL_RHARD);
255 spin(10000); /* give the controller some time to settle down from reset */
256
257 for(i=0;i<1000;i++){
258 spin(100000);
259 status = inb(BL_STATUS_REG);
260 if(status & BL_STATUS_DACT){
261 dprintf(".");
262 continue;
263 }
264 if(status & BL_STATUS_DFAIL){
265 dprintf(" FAILED\n");
266 return -1;
267 }
268 if(status & BL_STATUS_INREQ){
269 dprintf(" OKAY\n");
270 break;
271 }
272 if(status & BL_STATUS_HARDY) {
273 dprintf(" READY\n");
274 break;
275 }
276 }
277 if(i==100) {
278 dprintf(" TIMEOUT\n");
279 return -1;
280 }
281
282 if(bl_execute(bl, 0x04, NULL, 0, id, 4)){
283 d_printf("buslogic: can't id?\n");
284 return B_ERROR;
285 }
286 d_printf("buslogic: Firmware Rev %c.%c\n",id[2],id[3]);
287
288 id[0]=14;
289 id[14]=id[2];
290
291 if(bl_execute(bl, 0x8d, id, 1, id, 14)){
292 d_printf("buslogic: cannot read extended config\n");
293 return B_ERROR;
294 }
295
296 d_printf("buslogic: rev = %c.%c%c%c mb = %d, sgmax = %d, flags = 0x%02x\n",
297 id[14], id[10], id[11], id[12], id[4], id[2] | (id[3]<<8), id[13]);
298 if(id[13] & 0x01) bl->wide = 1;
299 else bl->wide = 0;
300
301 if(id[14] == '5'){
302 *str++ = 'B';
303 *str++ = 'T';
304 *str++ = '-';
305 *str++ = '9';
306 *str++ = bl->wide ? '5' : '4';
307 *str++ = '8';
308 if(id[13] & 0x02) *str++ = 'D';
309 *str++ = ' ';
310 *str++ = 'v';
311 *str++ = id[14];
312 *str++ = '.';
313 *str++ = id[10];
314 *str++ = id[11];
315 *str++ = id[12];
316 *str++ = 0;
317 } else {
318 strcpy(str,"unknown");
319 }
320 if(bl_execute(bl, 0x0B, NULL, 0, id, 3)){
321 d_printf("buslogic: cannot read config\n");
322 return B_ERROR;
323 }
324 bl->scsi_id = id[2];
325 d_printf("buslogic: Adapter SCSI ID = %d\n",bl->scsi_id);
326
327 if(install_io_interrupt_handler(bl->irq, scsi_int_dispatch, bl, 0)
328 == B_ERROR) d_printf("buslogic: can't install irq handler\n");
329
330 /* are we getting INTs? */
331 bl->done = 0;
332 spin(10000);
333 outb(BL_COMMAND_REG, 0x00);
334 spin(1000000);
335 if(bl->done) {
336 d_printf("buslogic: interrupt test passed\n");
337 } else {
338 d_printf("buslogic: interrupt test failed\n");
339 return B_ERROR;
340 }
341
342 /* strict round-robin on */
343 id[0] = 0;
344 if(bl_execute(bl,0x8F, id, 1, NULL, 0)){
345 d_printf("buslogic: cannot enable strict round-robin mode\n");
346 return B_ERROR;
347 }
348
349
350 id[0] = bl->box_count;
351 { int mbaddr = toLE(bl->phys_mailboxes);
352 memcpy(id + 1, &(mbaddr),4);
353 }
354 if(bl_execute(bl, 0x81, id, 5, NULL, 0)){
355 d_printf("buslogic: cannot init mailboxes\n");
356 return B_ERROR;
357 }
358 d_printf("buslogic: %d mailboxes @ 0x%08xv/0x%08lxp\n",
359 bl->box_count, (uint) bl->out_boxes, bl->phys_mailboxes);
360
361 return B_NO_ERROR;
362 }
363
364
365
366 /* sim_invalid()
367 **
368 ** Generic invalid XPT command response
369 */
sim_invalid(BusLogic * bl,CCB_HEADER * ccbh)370 static long sim_invalid(BusLogic *bl, CCB_HEADER *ccbh)
371 {
372 ccbh->cam_status = CAM_REQ_INVALID;
373 d_printf("sim_invalid\n");
374 return B_ERROR;
375 }
376
377
378 /* Convert a CCB_SCSIIO into a BL_CCB32 and (possibly SG array).
379 **
380 **
381 */
382
sim_execute_scsi_io(BusLogic * bl,CCB_HEADER * ccbh)383 static long sim_execute_scsi_io(BusLogic *bl, CCB_HEADER *ccbh)
384 {
385 CCB_SCSIIO *ccb;
386 int cdb_len;
387 BL_CCB32 *bl_ccb;
388 BL_PRIV *priv;
389 uint32 priv_phys;
390 uint32 bl_ccb_phys;
391 physical_entry entries[2];
392 physical_entry *scratch;
393 uint32 tmp;
394 int i,t,req;
395
396 ccb = (CCB_SCSIIO *) ccbh;
397
398 #ifdef DEBUG_BUSLOGIC
399 req = atomic_add(&(bl->reqid),1);
400 #endif
401
402 /* valid cdb len? */
403 cdb_len = ccb->cam_cdb_len;
404 if (cdb_len != 6 && cdb_len != 10 && cdb_len != 12) {
405 ccb->cam_ch.cam_status = CAM_REQ_INVALID;
406 return B_ERROR;
407 }
408
409 /* acquire a CCB32 block */
410 acquire_sem(bl->ccb_count);
411
412 /* protect the freelist and unchain the CCB32 from it */
413 acquire_sem(bl->ccb_lock);
414 bl_ccb = bl->first_ccb;
415 bl->first_ccb = bl_ccb->next;
416 release_sem(bl->ccb_lock);
417
418 bl_ccb_phys = VirtToPhys(bl_ccb);
419
420
421 /* get contiguous area for bl_ccb in the private data area */
422 get_memory_map((void *)ccb->cam_sim_priv, 4096, entries, 2);
423
424 priv_phys = (uint32) entries[0].address;
425 priv = (BL_PRIV *) ccb->cam_sim_priv;
426
427 /* copy over the CDB */
428 if(ccb->cam_ch.cam_flags & CAM_CDB_POINTER) {
429 memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_ptr, cdb_len);
430 } else {
431 memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_bytes, cdb_len);
432 }
433
434 /* fill out the ccb header */
435 bl_ccb->direction = BL_CCB_DIR_DEFAULT;
436 bl_ccb->length_cdb = cdb_len;
437 bl_ccb->length_sense = ccb->cam_sense_len;
438 bl_ccb->_reserved1 = bl_ccb->_reserved2 = 0;
439 bl_ccb->target_id = ccb->cam_ch.cam_target_id;
440 bl_ccb->lun_tag = ccb->cam_ch.cam_target_lun & 0x07;
441 bl_ccb->ccb_control = 0;
442 bl_ccb->link_id = 0;
443 bl_ccb->link = 0;
444 bl_ccb->sense = toLE(priv_phys);
445
446 /* okay, this is really disgusting and could potentially
447 break if physical_entry{} changes format... we use the
448 sg list as a scratchpad. Disgusting, but a start */
449
450 scratch = (physical_entry *) priv->sg;
451
452
453 if(ccb->cam_ch.cam_flags & CAM_SCATTER_VALID){
454 /* we're using scatter gather -- things just got trickier */
455 iovec *iov = (iovec *) ccb->cam_data_ptr;
456 int j,sgcount = 0;
457
458 /* dprintf("buslogic: sg count = %d\n",ccb->cam_sglist_cnt);*/
459 /* multiple entries, use SG */
460 bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG;
461 bl_ccb->data = toLE(priv_phys + 256);
462
463 /* for each entry in the sglist we were given ... */
464 for(t=0,i=0;i<ccb->cam_sglist_cnt;i++){
465 /* map it ... */
466 get_memory_map(iov[i].iov_base, iov[i].iov_len, &(scratch[sgcount]),
467 MAX_SCATTER - sgcount);
468
469 /* and make a bl sgentry for each chunk ... */
470 for(j=sgcount;scratch[j].size && j<MAX_SCATTER;j++){
471 t += scratch[j].size;
472 sgcount++;
473 dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req,
474 j, (uint32) scratch[j].address, scratch[j].size);
475
476 tmp = priv->sg[j].length;
477 priv->sg[j].length = toLE(priv->sg[j].phys);
478 priv->sg[j].phys = toLE(tmp);
479 }
480
481 if(scratch[j].size) panic("egads! sgseg overrun in BusLogic SIM");
482 }
483 if(t != ccb->cam_dxfer_len){
484 dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len);
485 ccb->cam_ch.cam_status = CAM_REQ_INVALID;
486
487 /* put the CCB32 back on the freelist and release our lock */
488 acquire_sem(bl->ccb_lock);
489 bl_ccb->next = bl->first_ccb;
490 bl->first_ccb = bl_ccb;
491 release_sem(bl->ccb_lock);
492 release_sem(bl->ccb_count);
493 return B_ERROR;
494 }
495 /* total bytes in DataSegList */
496 bl_ccb->length_data = toLE(sgcount * 8);
497 } else {
498 get_memory_map((void *)ccb->cam_data_ptr, ccb->cam_dxfer_len, scratch,
499 MAX_SCATTER);
500
501 if(scratch[1].size){
502 /* multiple entries, use SG */
503 bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG;
504 bl_ccb->data = toLE(priv_phys + 256);
505 for(t=0,i=0;scratch[i].size && i<MAX_SCATTER;i++){
506 t += scratch[i].size;
507 dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req,
508 i, (uint32) scratch[i].address, scratch[i].size);
509
510 tmp = priv->sg[i].length;
511 priv->sg[i].length = toLE(priv->sg[i].phys);
512 priv->sg[i].phys = toLE(tmp);
513 }
514 if(t != ccb->cam_dxfer_len){
515 dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len);
516 ccb->cam_ch.cam_status = CAM_REQ_INVALID;
517
518 /* put the CCB32 back on the freelist and release our lock */
519 acquire_sem(bl->ccb_lock);
520 bl_ccb->next = bl->first_ccb;
521 bl->first_ccb = bl_ccb;
522 release_sem(bl->ccb_lock);
523 release_sem(bl->ccb_count);
524 return B_ERROR;
525 }
526 /* total bytes in DataSegList */
527 bl_ccb->length_data = toLE(i * 8);
528
529 } else {
530 bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN;
531 /* single entry, use direct */
532 t = bl_ccb->length_data = toLE(ccb->cam_dxfer_len);
533 bl_ccb->data = toLE((uint32) scratch[0].address);
534 }
535 }
536
537 dt_printf("buslogic/%d: targ %d, dxfr %d, scsi op = 0x%02x\n",req,
538 bl_ccb->target_id, t, bl_ccb->cdb[0]);
539
540 acquire_sem(bl->hw_lock);
541
542 /* check for box in use state XXX */
543 bl->out_boxes[bl->out_nextbox].ccb_phys = toLE(bl_ccb_phys);
544 bl->out_boxes[bl->out_nextbox].action_code = BL_ActionCode_Start;
545 bl->out_nextbox++;
546 if(bl->out_nextbox == bl->box_count) bl->out_nextbox = 0;
547 outb(BL_COMMAND_REG, 0x02);
548
549 #ifndef SERIALIZE_REQS
550 release_sem(bl->hw_lock);
551 #endif
552 /* d_printf("buslogic/%d: CCB %08x (%08xv) waiting on done\n",
553 req, bl_ccb_phys, (uint32) bl_ccb);*/
554 acquire_sem(bl_ccb->done);
555 /* d_printf("buslogic/%d: CCB %08x (%08xv) done\n",
556 req, bl_ccb_phys, (uint32) bl_ccb);*/
557
558 #ifdef SERIALIZE_REQS
559 release_sem(bl->hw_lock);
560 #endif
561
562 if(bl_ccb->btstat){
563 /* XXX - error state xlat goes here */
564 switch(bl_ccb->btstat){
565 case 0x11:
566 ccb->cam_ch.cam_status = CAM_SEL_TIMEOUT;
567 break;
568 case 0x12:
569 ccb->cam_ch.cam_status = CAM_DATA_RUN_ERR;
570 break;
571 case 0x13:
572 ccb->cam_ch.cam_status = CAM_UNEXP_BUSFREE;
573 break;
574 case 0x22:
575 case 0x23:
576 ccb->cam_ch.cam_status = CAM_SCSI_BUS_RESET;
577 break;
578 case 0x34:
579 ccb->cam_ch.cam_status = CAM_UNCOR_PARITY;
580 break;
581 default:
582 ccb->cam_ch.cam_status = CAM_REQ_INVALID;
583 }
584 dt_printf("buslogic/%d: error stat %02x\n",req,bl_ccb->btstat);
585 } else {
586 dt_printf("buslogic/%d: data %d/%d, sense %d/%d\n", req,
587 bl_ccb->length_data, ccb->cam_dxfer_len,
588 bl_ccb->length_sense, ccb->cam_sense_len);
589
590 ccb->cam_resid = bl_ccb->length_data;
591
592 /* under what condition should we do this? */
593 memcpy(ccb->cam_sense_ptr, priv->sensedata, ccb->cam_sense_len);
594
595 ccb->cam_scsi_status = bl_ccb->sdstat;
596
597 if(bl_ccb->sdstat == 02){
598 ccb->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID;
599 ccb->cam_sense_resid = 0;
600 dt_printf("buslogic/%d: error scsi\n",req);
601 } else {
602 ccb->cam_ch.cam_status = CAM_REQ_CMP;
603 ccb->cam_sense_resid = bl_ccb->length_sense;
604 dt_printf("buslogic/%d: success scsi\n",req);
605 /* put the CCB32 back on the freelist and release our lock */
606 acquire_sem(bl->ccb_lock);
607 bl_ccb->next = bl->first_ccb;
608 bl->first_ccb = bl_ccb;
609 release_sem(bl->ccb_lock);
610 release_sem(bl->ccb_count);
611 return 0;
612
613 }
614 }
615
616 /* put the CCB32 back on the freelist and release our lock */
617 acquire_sem(bl->ccb_lock);
618 bl_ccb->next = bl->first_ccb;
619 bl->first_ccb = bl_ccb;
620 release_sem(bl->ccb_lock);
621 release_sem(bl->ccb_count);
622 return B_ERROR;
623 }
624
625
626 /*
627 ** sim_path_inquiry returns info on the target/lun.
628 */
sim_path_inquiry(BusLogic * bl,CCB_HEADER * ccbh)629 static long sim_path_inquiry(BusLogic *bl, CCB_HEADER *ccbh)
630 {
631 CCB_PATHINQ *ccb;
632 d_printf("buslogic: sim_path_inquiry()\n");
633
634 ccb = (CCB_PATHINQ *) ccbh;
635
636 ccb->cam_version_num = SIM_VERSION;
637 ccb->cam_target_sprt = 0;
638 ccb->cam_hba_eng_cnt = 0;
639 memset (ccb->cam_vuhba_flags, 0, VUHBA);
640 ccb->cam_sim_priv = SIM_PRIV;
641 ccb->cam_async_flags = 0;
642 ccb->cam_initiator_id = bl->scsi_id;
643 ccb->cam_hba_inquiry = bl->wide ? PI_WIDE_16 : 0;
644 strncpy (ccb->cam_sim_vid, sim_vendor_name, SIM_ID);
645 strncpy (ccb->cam_hba_vid, hba_vendor_name, HBA_ID);
646 ccb->cam_osd_usage = 0;
647 ccbh->cam_status = CAM_REQ_CMP;
648 return 0;
649 }
650
651
652 /*
653 ** sim_extended_path_inquiry returns info on the target/lun.
654 */
sim_extended_path_inquiry(BusLogic * bl,CCB_HEADER * ccbh)655 static long sim_extended_path_inquiry(BusLogic *bl, CCB_HEADER *ccbh)
656 {
657 CCB_EXTENDED_PATHINQ *ccb;
658
659 sim_path_inquiry(bl, ccbh);
660 ccb = (CCB_EXTENDED_PATHINQ *) ccbh;
661 sprintf(ccb->cam_sim_version, "%d.0", SIM_VERSION);
662 sprintf(ccb->cam_hba_version, "%d.0", HBA_VERSION);
663 strncpy(ccb->cam_controller_family, controller_family, FAM_ID);
664 strncpy(ccb->cam_controller_type, bl->productname, TYPE_ID);
665 return 0;
666 }
667
668
669 /*
670 ** sim_release_queue unfreezes the target/lun's request queue.
671 */
sim_sim_release_queue(BusLogic * bl,CCB_HEADER * ccbh)672 static long sim_sim_release_queue(BusLogic *bl, CCB_HEADER *ccbh)
673 {
674 ccbh->cam_status = CAM_REQ_INVALID;
675 return B_ERROR;
676 }
677
678
679 /*
680 ** sim_set_async_callback registers a callback routine for the
681 ** target/lun;
682 */
sim_set_async_callback(BusLogic * bl,CCB_HEADER * ccbh)683 static long sim_set_async_callback(BusLogic *bl, CCB_HEADER *ccbh)
684 {
685 ccbh->cam_status = CAM_REQ_INVALID;
686 return B_ERROR;
687 }
688
689
690 /*
691 ** sim_abort aborts a pending or queued scsi operation.
692 */
sim_abort(BusLogic * bl,CCB_HEADER * ccbh)693 static long sim_abort(BusLogic *bl, CCB_HEADER *ccbh)
694 {
695 ccbh->cam_status = CAM_REQ_INVALID;
696 return B_ERROR;
697 }
698
699
700 /*
701 ** sim_reset_bus resets the scsi bus.
702 */
sim_reset_bus(BusLogic * bl,CCB_HEADER * ccbh)703 static long sim_reset_bus(BusLogic *bl, CCB_HEADER *ccbh)
704 {
705 ccbh->cam_status = CAM_REQ_CMP;
706 return 0;
707 }
708
709
710 /*
711 ** sim_reset_device resets the target/lun with the scsi "bus
712 ** device reset" command.
713 */
sim_reset_device(BusLogic * bl,CCB_HEADER * ccbh)714 static long sim_reset_device(BusLogic *bl, CCB_HEADER *ccbh)
715 {
716 ccbh->cam_status = CAM_REQ_INVALID;
717 return B_ERROR;
718 }
719
720
721 /*
722 ** sim_terminate_process terminates the scsi i/o request without
723 ** corrupting the medium. It is used to stop lengthy requests
724 ** when a higher priority request is available.
725 **
726 ** Not yet implemented.
727 */
sim_terminate_process(BusLogic * bl,CCB_HEADER * ccbh)728 static long sim_terminate_process(BusLogic *bl, CCB_HEADER *ccbh)
729 {
730 ccbh->cam_status = CAM_REQ_INVALID;
731 return B_ERROR;
732 }
733
734
735 /*
736 ** scsi_sim_action performes the scsi i/o command embedded in the
737 ** passed ccb.
738 **
739 ** The target/lun ids are assumed to be in range.
740 */
sim_action(BusLogic * bl,CCB_HEADER * ccbh)741 static long sim_action(BusLogic *bl, CCB_HEADER *ccbh)
742 {
743 static long (*sim_functions[])(BusLogic *, CCB_HEADER *) = {
744 sim_invalid, /* do nothing */
745 sim_execute_scsi_io, /* execute a scsi i/o command */
746 sim_invalid, /* get device type info */
747 sim_path_inquiry, /* path inquiry */
748 sim_sim_release_queue, /* release a frozen SIM queue */
749 sim_set_async_callback, /* set async callback parameters */
750 sim_invalid, /* set device type info */
751 sim_invalid, /* invalid function code */
752 sim_invalid, /* invalid function code */
753 sim_invalid, /* invalid function code */
754 sim_invalid, /* invalid function code */
755 sim_invalid, /* invalid function code */
756 sim_invalid, /* invalid function code */
757 sim_invalid, /* invalid function code */
758 sim_invalid, /* invalid function code */
759 sim_invalid, /* invalid function code */
760 sim_abort, /* abort the selected CCB */
761 sim_reset_bus, /* reset a SCSI bus */
762 sim_reset_device, /* reset a SCSI device */
763 sim_terminate_process /* terminate an i/o process */
764 };
765 uchar op;
766
767 /* d_printf("buslogic: sim_execute(), op = %d\n", ccbh->cam_func_code); */
768
769 /* check for function codes out of range of dispatch table */
770 op = ccbh->cam_func_code;
771 if ((op >= sizeof (sim_functions) / sizeof (long (*)())) &&
772 (op != XPT_EXTENDED_PATH_INQ)) {
773 /* check for our vendor-uniques (if any) here... */
774 ccbh->cam_status = CAM_REQ_INVALID;
775 return -1;
776 }
777
778 ccbh->cam_status = CAM_REQ_INPROG;
779 if (op == XPT_EXTENDED_PATH_INQ) {
780 return sim_extended_path_inquiry(bl, ccbh);
781 } else {
782 return (*sim_functions [op])(bl, ccbh);
783 }
784 }
785
786
787 static char *hextab = "0123456789ABCDEF";
788
789 /*
790 ** Allocate the actual memory for the cardinfo object
791 */
create_cardinfo(int num,int iobase,int irq)792 static BusLogic *create_cardinfo(int num, int iobase, int irq)
793 {
794 uchar *a;
795 area_id aid;
796 int i;
797 physical_entry entries[5];
798 char name[9] = { 'b', 'l', '_', 'c', 'c', 'b', '0', '0', 0 };
799
800 BusLogic *bl = (BusLogic *) malloc(sizeof(BusLogic));
801
802 #ifndef __i386__
803 i = map_physical_memory("bl_regs", iobase, 4096,
804 B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, &a);
805 iobase = (uint32) a;
806 if(i < 0) {
807 dprintf("buslogic: can't map registers...\n");
808 }
809 #endif
810
811 bl->id = num;
812 bl->iobase = iobase;
813 bl->irq = irq;
814 bl->out_nextbox = bl->in_nextbox = 0;
815
816 /* create our 20k workspace. First 4k goes to 510 mailboxes.
817 ** remaining 16k is used for up to 256 CCB32's
818 */
819 a = NULL;
820
821 #if BOOT
822 /* life in the bootstrap is a bit different... */
823 /* can't be sure of getting contig pages -- scale
824 stuff down so we can live in just one page */
825 bl->box_count = 4;
826 if(!(a = malloc(4096*2))) {
827 free(bl);
828 return NULL;
829 }
830 a = (uchar *) ((((uint32) a) & 0xFFFFF000) + 0x1000);
831 get_memory_map(a, 4096, entries, 2);
832 #else
833 bl->box_count = MAX_CCB_COUNT;
834 aid = create_area("bl_workspace", (void **)&a, B_ANY_KERNEL_ADDRESS, 4096*5,
835 B_32_BIT_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
836 if(aid == B_ERROR || aid == B_BAD_VALUE || aid == B_NO_MEMORY) {
837 free(bl);
838 return NULL;
839 }
840 get_memory_map(a, 4096*5, entries, 2);
841 #endif
842
843 /* figure virtual <-> physical translations */
844 bl->phys_to_virt = ((uint) a) - ((uint) entries[0].address);
845 bl->virt_to_phys = (((uint) entries[0].address - (uint) a));
846 bl->phys_mailboxes = (uint) entries[0].address;
847
848 /* initialize all mailboxes to empty */
849 bl->out_boxes = (BL_Out_Mailbox32 *) a;
850 bl->in_boxes = (BL_In_Mailbox32 *) (a + (8 * bl->box_count));
851 for(i=0;i<bl->box_count;i++){
852 bl->out_boxes[i].action_code = BL_ActionCode_NotInUse;
853 bl->in_boxes[i].completion_code = BL_CompletionCode_NotInUse;
854 }
855
856 /* setup the CCB32 cache */
857 #if BOOT
858 bl->ccb = (BL_CCB32 *) (((uchar *)a) + 1024);
859 #else
860 bl->ccb = (BL_CCB32 *) (((uchar *)a) + 4096);
861 #endif
862 bl->first_ccb = NULL;
863 for(i=0;i<bl->box_count;i++){
864 name[6] = hextab[(i & 0xF0) >> 4];
865 name[7] = hextab[i & 0x0F];
866 bl->ccb[i].done = create_sem(0, name);
867 bl->ccb[i].next = bl->first_ccb;
868 bl->first_ccb = &(bl->ccb[i]);
869 }
870
871 bl->hw_lock = create_sem(1, "bl_hw_lock");
872 bl->ccb_lock = create_sem(1, "bl_ccb_lock");
873 bl->ccb_count = create_sem(MAX_CCB_COUNT, "bl_ccb_count");
874 bl->reqid = 0;
875
876 return bl;
877 }
878
879
880 /*
881 ** Multiple Card Cruft
882 */
883 #define MAXCARDS 4
884
885 static BusLogic *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
886
sim_init0(void)887 static long sim_init0(void) { return init_buslogic(cardinfo[0]); }
sim_init1(void)888 static long sim_init1(void) { return init_buslogic(cardinfo[1]); }
sim_init2(void)889 static long sim_init2(void) { return init_buslogic(cardinfo[2]); }
sim_init3(void)890 static long sim_init3(void) { return init_buslogic(cardinfo[3]); }
sim_action0(CCB_HEADER * ccbh)891 static long sim_action0(CCB_HEADER *ccbh) { return sim_action(cardinfo[0],ccbh); }
sim_action1(CCB_HEADER * ccbh)892 static long sim_action1(CCB_HEADER *ccbh) { return sim_action(cardinfo[1],ccbh); }
sim_action2(CCB_HEADER * ccbh)893 static long sim_action2(CCB_HEADER *ccbh) { return sim_action(cardinfo[2],ccbh); }
sim_action3(CCB_HEADER * ccbh)894 static long sim_action3(CCB_HEADER *ccbh) { return sim_action(cardinfo[3],ccbh); }
895
896
897 static long (*sim_init_funcs[MAXCARDS])(void) = {
898 sim_init0, sim_init1, sim_init2, sim_init3
899 };
900
901 static long (*sim_action_funcs[MAXCARDS])(CCB_HEADER *) = {
902 sim_action0, sim_action1, sim_action2, sim_action3
903 };
904
905
906 /*
907 ** Detect the controller and register the SIM with the CAM layer.
908 ** returns the number of controllers installed...
909 */
910 static int
sim_install_buslogic(void)911 sim_install_buslogic(void)
912 {
913 int i, iobase, irq;
914 int cardcount = 0;
915 pci_info h;
916 CAM_SIM_ENTRY entry;
917
918 /* d_printf("buslogic: sim_install()\n"); */
919
920 for (i = 0; ; i++) {
921 if ((*pci->get_nth_pci_info) (i, &h) != B_NO_ERROR) {
922 /* if(!cardcount) d_printf("buslogic: no controller found\n"); */
923 break;
924 }
925
926 if ((h.vendor_id == PCI_VENDOR_BUSLOGIC) &&
927 (h.device_id == PCI_DEVICE_MULTIMASTER)) {
928
929 #ifdef __i386__
930 iobase = h.u.h0.base_registers[0];
931 #else
932 iobase = h.u.h0.base_registers[1];
933 #endif
934 irq = h.u.h0.interrupt_line;
935
936 d_printf("buslogic%d: controller @ 0x%08x, irq %d\n",
937 cardcount, iobase, irq);
938 if((irq == 0) || (irq > 128)) {
939 dprintf("buslogic%d: bad irq %d\n",cardcount,irq);
940 continue;
941 }
942
943 if(cardcount == MAXCARDS){
944 d_printf("buslogic: too many controllers!\n");
945 return cardcount;
946 }
947
948 if((cardinfo[cardcount] = create_cardinfo(cardcount,iobase,irq))){
949 entry.sim_init = sim_init_funcs[cardcount];
950 entry.sim_action = sim_action_funcs[cardcount];
951 (*cam->xpt_bus_register)(&entry);
952 cardcount++;
953 } else {
954 d_printf("buslogic: cannot allocate cardinfo\n");
955 }
956 }
957 }
958
959 return cardcount;
960 }
961
std_ops(int32 op,...)962 static status_t std_ops(int32 op, ...)
963 {
964 switch(op) {
965 case B_MODULE_INIT:
966 if (get_module(pci_name, (module_info **) &pci) != B_OK)
967 return B_ERROR;
968
969 if (get_module(cam_name, (module_info **) &cam) != B_OK) {
970 put_module(pci_name);
971 return B_ERROR;
972 }
973
974 if(sim_install_buslogic()){
975 return B_OK;
976 }
977
978 put_module(pci_name);
979 put_module(cam_name);
980 return B_ERROR;
981
982 case B_MODULE_UNINIT:
983 put_module(pci_name);
984 put_module(cam_name);
985 return B_OK;
986
987 default:
988 return B_ERROR;
989 }
990 }
991
992 #if BUILD_LOADABLE
993 static
994 #endif
995 sim_module_info sim_buslogic_module = {
996 { "busses/scsi/buslogic/v1", 0, &std_ops }
997 };
998
999 #if BUILD_LOADABLE
1000 _EXPORT module_info *modules[] =
1001 {
1002 (module_info *) &sim_buslogic_module,
1003 NULL
1004 };
1005 #endif
1006