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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 887 static long sim_init0(void) { return init_buslogic(cardinfo[0]); } 888 static long sim_init1(void) { return init_buslogic(cardinfo[1]); } 889 static long sim_init2(void) { return init_buslogic(cardinfo[2]); } 890 static long sim_init3(void) { return init_buslogic(cardinfo[3]); } 891 static long sim_action0(CCB_HEADER *ccbh) { return sim_action(cardinfo[0],ccbh); } 892 static long sim_action1(CCB_HEADER *ccbh) { return sim_action(cardinfo[1],ccbh); } 893 static long sim_action2(CCB_HEADER *ccbh) { return sim_action(cardinfo[2],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 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 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