1 /* 2 * Inline routines shareable across OS platforms. 3 * 4 * Copyright (c) 1994-2001 Justin T. Gibbs. 5 * Copyright (c) 2000-2001 Adaptec Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification. 14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 15 * substantially similar to the "NO WARRANTY" disclaimer below 16 * ("Disclaimer") and any redistribution must be conditioned upon 17 * including a substantially similar Disclaimer requirement for further 18 * binary redistribution. 19 * 3. Neither the names of the above-listed copyright holders nor the names 20 * of any contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * Alternatively, this software may be distributed under the terms of the 24 * GNU General Public License ("GPL") version 2 as published by the Free 25 * Software Foundation. 26 * 27 * NO WARRANTY 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 37 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGES. 39 * 40 * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#27 $ 41 * 42 * $FreeBSD$ 43 */ 44 45 #ifndef _AIC79XX_INLINE_H_ 46 #define _AIC79XX_INLINE_H_ 47 48 /******************************** Debugging ***********************************/ 49 static __inline char *ahd_name(struct ahd_softc *ahd); 50 51 static __inline char * 52 ahd_name(struct ahd_softc *ahd) 53 { 54 return (ahd->name); 55 } 56 57 /************************ Sequencer Execution Control *************************/ 58 static __inline void ahd_known_modes(struct ahd_softc *ahd, 59 ahd_mode src, ahd_mode dst); 60 static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, 61 ahd_mode src, 62 ahd_mode dst); 63 static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, 64 ahd_mode_state state, 65 ahd_mode *src, ahd_mode *dst); 66 static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, 67 ahd_mode dst); 68 static __inline void ahd_update_modes(struct ahd_softc *ahd); 69 static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 70 ahd_mode dstmode, const char *file, 71 int line); 72 static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); 73 static __inline void ahd_restore_modes(struct ahd_softc *ahd, 74 ahd_mode_state state); 75 static __inline int ahd_is_paused(struct ahd_softc *ahd); 76 static __inline void ahd_pause(struct ahd_softc *ahd); 77 static __inline void ahd_unpause(struct ahd_softc *ahd); 78 79 static __inline void 80 ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 81 { 82 ahd->src_mode = src; 83 ahd->dst_mode = dst; 84 ahd->saved_src_mode = src; 85 ahd->saved_dst_mode = dst; 86 } 87 88 static __inline ahd_mode_state 89 ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 90 { 91 return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); 92 } 93 94 static __inline void 95 ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, 96 ahd_mode *src, ahd_mode *dst) 97 { 98 *src = (state & SRC_MODE) >> SRC_MODE_SHIFT; 99 *dst = (state & DST_MODE) >> DST_MODE_SHIFT; 100 } 101 102 static __inline void 103 ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 104 { 105 if (ahd->src_mode == src && ahd->dst_mode == dst) 106 return; 107 #ifdef AHD_DEBUG 108 if (ahd->src_mode == AHD_MODE_UNKNOWN 109 || ahd->dst_mode == AHD_MODE_UNKNOWN) 110 panic("Setting mode prior to saving it.\n"); 111 if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 112 printf("Setting mode 0x%x\n", 113 ahd_build_mode_state(ahd, src, dst)); 114 #endif 115 ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); 116 ahd->src_mode = src; 117 ahd->dst_mode = dst; 118 } 119 120 static __inline void 121 ahd_update_modes(struct ahd_softc *ahd) 122 { 123 ahd_mode_state mode_ptr; 124 ahd_mode src; 125 ahd_mode dst; 126 127 mode_ptr = ahd_inb(ahd, MODE_PTR); 128 #ifdef AHD_DEBUG 129 if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 130 printf("Reading mode 0x%x\n", mode_ptr); 131 #endif 132 ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); 133 ahd_known_modes(ahd, src, dst); 134 } 135 136 static __inline void 137 ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 138 ahd_mode dstmode, const char *file, int line) 139 { 140 #ifdef AHD_DEBUG 141 if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 142 || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { 143 panic("%s:%s:%d: Mode assertion failed.\n", 144 ahd_name(ahd), file, line); 145 } 146 #endif 147 } 148 149 static __inline ahd_mode_state 150 ahd_save_modes(struct ahd_softc *ahd) 151 { 152 if (ahd->src_mode == AHD_MODE_UNKNOWN 153 || ahd->dst_mode == AHD_MODE_UNKNOWN) 154 ahd_update_modes(ahd); 155 156 return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); 157 } 158 159 static __inline void 160 ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) 161 { 162 ahd_mode src; 163 ahd_mode dst; 164 165 ahd_extract_mode_state(ahd, state, &src, &dst); 166 ahd_set_modes(ahd, src, dst); 167 } 168 169 #define AHD_ASSERT_MODES(ahd, source, dest) \ 170 ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); 171 172 /* 173 * Determine whether the sequencer has halted code execution. 174 * Returns non-zero status if the sequencer is stopped. 175 */ 176 static __inline int 177 ahd_is_paused(struct ahd_softc *ahd) 178 { 179 return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); 180 } 181 182 /* 183 * Request that the sequencer stop and wait, indefinitely, for it 184 * to stop. The sequencer will only acknowledge that it is paused 185 * once it has reached an instruction boundary and PAUSEDIS is 186 * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 187 * for critical sections. 188 */ 189 static __inline void 190 ahd_pause(struct ahd_softc *ahd) 191 { 192 ahd_outb(ahd, HCNTRL, ahd->pause); 193 194 /* 195 * Since the sequencer can disable pausing in a critical section, we 196 * must loop until it actually stops. 197 */ 198 while (ahd_is_paused(ahd) == 0) 199 ; 200 } 201 202 /* 203 * Allow the sequencer to continue program execution. 204 * We check here to ensure that no additional interrupt 205 * sources that would cause the sequencer to halt have been 206 * asserted. If, for example, a SCSI bus reset is detected 207 * while we are fielding a different, pausing, interrupt type, 208 * we don't want to release the sequencer before going back 209 * into our interrupt handler and dealing with this new 210 * condition. 211 */ 212 static __inline void 213 ahd_unpause(struct ahd_softc *ahd) 214 { 215 /* 216 * Automatically restore our modes to those saved 217 * prior to the first change of the mode. 218 */ 219 if (ahd->saved_src_mode != AHD_MODE_UNKNOWN 220 && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) 221 ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 222 223 if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0) 224 ahd_outb(ahd, HCNTRL, ahd->unpause); 225 226 ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 227 } 228 229 /*********************** Untagged Transaction Routines ************************/ 230 static __inline void ahd_freeze_untagged_queues(struct ahd_softc *ahd); 231 static __inline void ahd_release_untagged_queues(struct ahd_softc *ahd); 232 233 /* 234 * Block our completion routine from starting the next untagged 235 * transaction for this target or target lun. 236 */ 237 static __inline void 238 ahd_freeze_untagged_queues(struct ahd_softc *ahd) 239 { 240 /* 241 * Assume we have enough space in the card's SCB 242 * to obviate the need for a per target untagged 243 * transaction limit. 244 */ 245 #if 0 246 ahd->untagged_queue_lock++; 247 #endif 248 } 249 250 /* 251 * Allow the next untagged transaction for this target or target lun 252 * to be executed. We use a counting semaphore to allow the lock 253 * to be acquired recursively. Once the count drops to zero, the 254 * transaction queues will be run. 255 */ 256 static __inline void 257 ahd_release_untagged_queues(struct ahd_softc *ahd) 258 { 259 /* 260 * Assume we have enough space in the card's SCB 261 * to obviate the need for a per target untagged 262 * transaction limit. 263 */ 264 #if 0 265 ahd->untagged_queue_lock--; 266 if (ahd->untagged_queue_lock == 0) 267 ahd_run_untagged_queues(ahd); 268 #endif 269 } 270 271 /*********************** Scatter Gather List Handling *************************/ 272 static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 273 void *sgptr, bus_addr_t addr, 274 bus_size_t len, int last); 275 static __inline void ahd_setup_scb_common(struct ahd_softc *ahd, 276 struct scb *scb); 277 static __inline void ahd_setup_data_scb(struct ahd_softc *ahd, 278 struct scb *scb); 279 static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, 280 struct scb *scb); 281 282 static __inline void * 283 ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 284 void *sgptr, bus_addr_t addr, bus_size_t len, int last) 285 { 286 scb->sg_count++; 287 if (sizeof(bus_addr_t) > 4 288 && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 289 struct ahd_dma64_seg *sg; 290 291 sg = (struct ahd_dma64_seg *)sgptr; 292 sg->addr = ahd_htole64(addr); 293 sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 294 return (sg + 1); 295 } else { 296 struct ahd_dma_seg *sg; 297 298 sg = (struct ahd_dma_seg *)sgptr; 299 sg->addr = ahd_htole64(addr); 300 sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) 301 | (last ? AHD_DMA_LAST_SEG : 0)); 302 return (sg + 1); 303 } 304 } 305 306 static __inline void 307 ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 308 { 309 /* XXX Handle target mode SCBs. */ 310 if ((scb->flags & SCB_PACKETIZED) != 0) { 311 /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 312 scb->hscb->task_attribute_nonpkt_tag = 313 scb->hscb->control & SCB_TAG_TYPE; 314 scb->hscb->task_management = 0; 315 } else { 316 scb->hscb->task_attribute_nonpkt_tag = SCB_GET_TAG(scb); 317 } 318 319 if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 320 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 321 scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 322 ahd_htole32(scb->sense_busaddr); 323 } 324 325 static __inline void 326 ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 327 { 328 /* 329 * Copy the first SG into the "current" data ponter area. 330 */ 331 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 332 struct ahd_dma64_seg *sg; 333 334 sg = (struct ahd_dma64_seg *)scb->sg_list; 335 scb->hscb->dataptr = sg->addr; 336 scb->hscb->datacnt = sg->len; 337 } else { 338 struct ahd_dma_seg *sg; 339 340 sg = (struct ahd_dma_seg *)scb->sg_list; 341 scb->hscb->dataptr = sg->addr; 342 if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 343 uint64_t high_addr; 344 345 high_addr = (ahd_le32toh(sg->len) & 0x7F000000) << 8; 346 scb->hscb->dataptr |= ahd_htole64(high_addr); 347 } 348 scb->hscb->datacnt = sg->len; 349 } 350 /* 351 * Note where to find the SG entries in bus space. 352 * We also set the full residual flag which the 353 * sequencer will clear as soon as a data transfer 354 * occurs. 355 */ 356 scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 357 } 358 359 static __inline void 360 ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 361 { 362 scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 363 scb->hscb->dataptr = 0; 364 scb->hscb->datacnt = 0; 365 } 366 367 /************************** Memory mapping routines ***************************/ 368 static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 369 static __inline void * 370 ahd_sg_bus_to_virt(struct ahd_softc *ahd, 371 struct scb *scb, 372 uint32_t sg_busaddr); 373 static __inline uint32_t 374 ahd_sg_virt_to_bus(struct ahd_softc *ahd, 375 struct scb *scb, 376 void *sg); 377 static __inline void ahd_sync_scb(struct ahd_softc *ahd, 378 struct scb *scb, int op); 379 static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 380 struct scb *scb, int op); 381 static __inline void ahd_sync_sense(struct ahd_softc *ahd, 382 struct scb *scb, int op); 383 static __inline uint32_t 384 ahd_targetcmd_offset(struct ahd_softc *ahd, 385 u_int index); 386 387 static __inline size_t 388 ahd_sg_size(struct ahd_softc *ahd) 389 { 390 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 391 return (sizeof(struct ahd_dma64_seg)); 392 return (sizeof(struct ahd_dma_seg)); 393 } 394 395 static __inline void * 396 ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 397 { 398 bus_addr_t sg_offset; 399 400 /* sg_list_phys points to entry 1, not 0 */ 401 sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 402 return ((uint8_t *)scb->sg_list + sg_offset); 403 } 404 405 static __inline uint32_t 406 ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 407 { 408 bus_addr_t sg_offset; 409 410 /* sg_list_phys points to entry 1, not 0 */ 411 sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 412 - ahd_sg_size(ahd); 413 414 return (scb->sg_list_busaddr + sg_offset); 415 } 416 417 static __inline void 418 ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 419 { 420 ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 421 scb->hscb_map->dmamap, 422 /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 423 /*len*/sizeof(*scb->hscb), op); 424 } 425 426 static __inline void 427 ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 428 { 429 if (scb->sg_count == 0) 430 return; 431 432 ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 433 scb->sg_map->dmamap, 434 /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 435 /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 436 } 437 438 static __inline void 439 ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 440 { 441 ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 442 scb->sense_map->dmamap, 443 /*offset*/scb->sense_busaddr, 444 /*len*/AHD_SENSE_BUFSIZE, op); 445 } 446 447 static __inline uint32_t 448 ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 449 { 450 return (((uint8_t *)&ahd->targetcmds[index]) 451 - (uint8_t *)ahd->qoutfifo); 452 } 453 454 /*********************** Miscelaneous Support Functions ***********************/ 455 static __inline void ahd_complete_scb(struct ahd_softc *ahd, 456 struct scb *scb); 457 static __inline void ahd_update_residual(struct ahd_softc *ahd, 458 struct scb *scb); 459 static __inline struct ahd_initiator_tinfo * 460 ahd_fetch_transinfo(struct ahd_softc *ahd, 461 char channel, u_int our_id, 462 u_int remote_id, 463 struct ahd_tmode_tstate **tstate); 464 static __inline struct scb* 465 ahd_get_scb(struct ahd_softc *ahd); 466 static __inline void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); 467 static __inline uint16_t 468 ahd_inw(struct ahd_softc *ahd, u_int port); 469 static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 470 u_int value); 471 static __inline uint32_t 472 ahd_inl(struct ahd_softc *ahd, u_int port); 473 static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 474 uint32_t value); 475 static __inline uint64_t 476 ahd_inq(struct ahd_softc *ahd, u_int port); 477 static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 478 uint64_t value); 479 static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 480 static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 481 static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 482 static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 483 static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 484 static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 485 static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 486 static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 487 static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 488 static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 489 static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 490 static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 491 static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 492 static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 493 static __inline uint32_t 494 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 495 static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 496 struct scb *scb); 497 static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 498 static __inline uint8_t * 499 ahd_get_sense_buf(struct ahd_softc *ahd, 500 struct scb *scb); 501 static __inline uint32_t 502 ahd_get_sense_bufaddr(struct ahd_softc *ahd, 503 struct scb *scb); 504 505 static __inline void 506 ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 507 { 508 uint32_t sgptr; 509 510 sgptr = ahd_le32toh(scb->hscb->sgptr); 511 if ((sgptr & SG_STATUS_VALID) != 0) 512 ahd_handle_scb_status(ahd, scb); 513 else 514 ahd_done(ahd, scb); 515 } 516 517 /* 518 * Determine whether the sequencer reported a residual 519 * for this SCB/transaction. 520 */ 521 static __inline void 522 ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 523 { 524 uint32_t sgptr; 525 526 sgptr = ahd_le32toh(scb->hscb->sgptr); 527 if ((sgptr & SG_STATUS_VALID) != 0) 528 ahd_calc_residual(ahd, scb); 529 } 530 531 /* 532 * Return pointers to the transfer negotiation information 533 * for the specified our_id/remote_id pair. 534 */ 535 static __inline struct ahd_initiator_tinfo * 536 ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 537 u_int remote_id, struct ahd_tmode_tstate **tstate) 538 { 539 /* 540 * Transfer data structures are stored from the perspective 541 * of the target role. Since the parameters for a connection 542 * in the initiator role to a given target are the same as 543 * when the roles are reversed, we pretend we are the target. 544 */ 545 if (channel == 'B') 546 our_id += 8; 547 *tstate = ahd->enabled_targets[our_id]; 548 return (&(*tstate)->transinfo[remote_id]); 549 } 550 551 /* 552 * Get a free scb. If there are none, see if we can allocate a new SCB. 553 */ 554 static __inline struct scb * 555 ahd_get_scb(struct ahd_softc *ahd) 556 { 557 struct scb *scb; 558 559 if ((scb = SLIST_FIRST(&ahd->scb_data.free_scbs)) == NULL) { 560 ahd_alloc_scbs(ahd); 561 scb = SLIST_FIRST(&ahd->scb_data.free_scbs); 562 if (scb == NULL) 563 return (NULL); 564 } 565 SLIST_REMOVE_HEAD(&ahd->scb_data.free_scbs, links.sle); 566 return (scb); 567 } 568 569 /* 570 * Return an SCB resource to the free list. 571 */ 572 static __inline void 573 ahd_free_scb(struct ahd_softc *ahd, struct scb *scb) 574 { 575 576 /* Clean up for the next user */ 577 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL; 578 scb->flags = SCB_FREE; 579 scb->hscb->control = 0; 580 581 SLIST_INSERT_HEAD(&ahd->scb_data.free_scbs, scb, links.sle); 582 583 /* Notify the OSM that a resource is now available. */ 584 ahd_platform_scb_free(ahd, scb); 585 } 586 587 static __inline uint16_t 588 ahd_inw(struct ahd_softc *ahd, u_int port) 589 { 590 return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 591 } 592 593 static __inline void 594 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 595 { 596 ahd_outb(ahd, port, value & 0xFF); 597 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 598 } 599 600 static __inline uint32_t 601 ahd_inl(struct ahd_softc *ahd, u_int port) 602 { 603 return ((ahd_inb(ahd, port)) 604 | (ahd_inb(ahd, port+1) << 8) 605 | (ahd_inb(ahd, port+2) << 16) 606 | (ahd_inb(ahd, port+3) << 24)); 607 } 608 609 static __inline void 610 ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 611 { 612 ahd_outb(ahd, port, (value) & 0xFF); 613 ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 614 ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 615 ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 616 } 617 618 static __inline uint64_t 619 ahd_inq(struct ahd_softc *ahd, u_int port) 620 { 621 return ((ahd_inb(ahd, port)) 622 | (ahd_inb(ahd, port+1) << 8) 623 | (ahd_inb(ahd, port+2) << 16) 624 | (ahd_inb(ahd, port+3) << 24) 625 | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 626 | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 627 | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 628 | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 629 } 630 631 static __inline void 632 ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 633 { 634 ahd_outb(ahd, port, value & 0xFF); 635 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 636 ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 637 ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 638 ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 639 ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 640 ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 641 ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 642 } 643 644 static __inline u_int 645 ahd_get_scbptr(struct ahd_softc *ahd) 646 { 647 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 648 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 649 return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 650 } 651 652 static __inline void 653 ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 654 { 655 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 656 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 657 ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 658 ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 659 } 660 661 static __inline u_int 662 ahd_get_hnscb_qoff(struct ahd_softc *ahd) 663 { 664 return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 665 } 666 667 static __inline void 668 ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 669 { 670 ahd_outw_atomic(ahd, HNSCB_QOFF, value); 671 } 672 673 static __inline u_int 674 ahd_get_hescb_qoff(struct ahd_softc *ahd) 675 { 676 return (ahd_inb(ahd, HESCB_QOFF)); 677 } 678 679 static __inline void 680 ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 681 { 682 ahd_outb(ahd, HESCB_QOFF, value); 683 } 684 685 static __inline u_int 686 ahd_get_snscb_qoff(struct ahd_softc *ahd) 687 { 688 u_int oldvalue; 689 690 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 691 oldvalue = ahd_inw(ahd, SNSCB_QOFF); 692 ahd_outw(ahd, SNSCB_QOFF, oldvalue); 693 return (oldvalue); 694 } 695 696 static __inline void 697 ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 698 { 699 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 700 ahd_outw(ahd, SNSCB_QOFF, value); 701 } 702 703 static __inline u_int 704 ahd_get_sescb_qoff(struct ahd_softc *ahd) 705 { 706 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 707 return (ahd_inb(ahd, SESCB_QOFF)); 708 } 709 710 static __inline void 711 ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 712 { 713 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 714 ahd_outb(ahd, SESCB_QOFF, value); 715 } 716 717 static __inline u_int 718 ahd_get_sdscb_qoff(struct ahd_softc *ahd) 719 { 720 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 721 return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 722 } 723 724 static __inline void 725 ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 726 { 727 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 728 ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 729 ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 730 } 731 732 static __inline u_int 733 ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 734 { 735 u_int value; 736 737 /* 738 * Workaround PCI-X Rev A. hardware bug. 739 * After a host read of SCB memory, the chip 740 * may become confused into thinking prefetch 741 * was required. This starts the discard timer 742 * running and can cause an unexpected discard 743 * timer interrupt. The work around is to read 744 * a normal register prior to the exhaustion of 745 * the discard timer. The mode pointer register 746 * has no side effects and so serves well for 747 * this purpose. 748 * 749 * Razor #528 750 */ 751 value = ahd_inb(ahd, offset); 752 ahd_inb(ahd, MODE_PTR); 753 return (value); 754 } 755 756 static __inline u_int 757 ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 758 { 759 return (ahd_inb_scbram(ahd, offset) 760 | (ahd_inb_scbram(ahd, offset+1) << 8)); 761 } 762 763 static __inline uint32_t 764 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 765 { 766 return (ahd_inb_scbram(ahd, offset) 767 | (ahd_inb_scbram(ahd, offset+1) << 8) 768 | (ahd_inb_scbram(ahd, offset+2) << 16) 769 | (ahd_inb_scbram(ahd, offset+3) << 24)); 770 } 771 772 static __inline struct scb * 773 ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 774 { 775 struct scb* scb; 776 777 if (tag >= AHD_SCB_MAX) 778 return (NULL); 779 scb = ahd->scb_data.scbindex[tag]; 780 if (scb != NULL) 781 ahd_sync_scb(ahd, scb, 782 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 783 return (scb); 784 } 785 786 static __inline void 787 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 788 { 789 struct hardware_scb *q_hscb; 790 uint32_t saved_hscb_busaddr; 791 792 /* 793 * Our queuing method is a bit tricky. The card 794 * knows in advance which HSCB (by address) to download, 795 * and we can't disappoint it. To achieve this, the next 796 * SCB to download is saved off in ahd->next_queued_scb. 797 * When we are called to queue "an arbitrary scb", 798 * we copy the contents of the incoming HSCB to the one 799 * the sequencer knows about, swap HSCB pointers and 800 * finally assign the SCB to the tag indexed location 801 * in the scb_array. This makes sure that we can still 802 * locate the correct SCB by SCB_TAG. 803 */ 804 q_hscb = ahd->next_queued_scb->hscb; 805 saved_hscb_busaddr = q_hscb->hscb_busaddr; 806 memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 807 q_hscb->hscb_busaddr = saved_hscb_busaddr; 808 q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 809 810 /* Now swap HSCB pointers. */ 811 ahd->next_queued_scb->hscb = scb->hscb; 812 scb->hscb = q_hscb; 813 814 /* Now define the mapping from tag to SCB in the scbindex */ 815 /* XXX This should be constant now. Can we avoid the mapping? */ 816 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 817 } 818 819 /* 820 * Tell the sequencer about a new transaction to execute. 821 */ 822 static __inline void 823 ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 824 { 825 ahd_swap_with_next_hscb(ahd, scb); 826 827 if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 828 panic("Attempt to queue invalid SCB tag %x\n", 829 SCB_GET_TAG(scb)); 830 831 /* 832 * Keep a history of SCBs we've downloaded in the qinfifo. 833 */ 834 ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 835 ahd->qinfifonext++; 836 837 if (scb->sg_count != 0) 838 ahd_setup_data_scb(ahd, scb); 839 else 840 ahd_setup_noxfer_scb(ahd, scb); 841 ahd_setup_scb_common(ahd, scb); 842 843 /* 844 * Make sure our data is consistant from the 845 * perspective of the adapter. 846 */ 847 ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 848 849 #ifdef AHD_DEBUG 850 if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 851 printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 852 ahd_name(ahd), 853 SCB_GET_TAG(scb), scb->hscb->hscb_busaddr, 854 (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF), 855 (u_int)(scb->hscb->dataptr & 0xFFFFFFFF), 856 scb->hscb->datacnt); 857 } 858 #endif 859 /* Tell the adapter about the newly queued SCB */ 860 ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 861 } 862 863 static __inline uint8_t * 864 ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 865 { 866 return (scb->sense_data); 867 } 868 869 static __inline uint32_t 870 ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 871 { 872 return (scb->sense_busaddr); 873 } 874 875 /************************** Interrupt Processing ******************************/ 876 static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 877 static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 878 static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 879 static __inline void ahd_intr(struct ahd_softc *ahd); 880 881 static __inline void 882 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 883 { 884 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 885 /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); 886 } 887 888 static __inline void 889 ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 890 { 891 #ifdef AHD_TARGET_MODE 892 if ((ahd->flags & AHD_TARGETROLE) != 0) { 893 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 894 ahd->shared_data_dmamap, 895 ahd_targetcmd_offset(ahd, 0), 896 sizeof(struct target_cmd) * AHD_TMODE_CMDS, 897 op); 898 } 899 #endif 900 } 901 902 /* 903 * See if the firmware has posted any completed commands 904 * into our in-core command complete fifos. 905 */ 906 #define AHD_RUN_QOUTFIFO 0x1 907 #define AHD_RUN_TQINFIFO 0x2 908 static __inline u_int 909 ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 910 { 911 u_int retval; 912 913 retval = 0; 914 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 915 /*offset*/ahd->qoutfifonext, /*len*/2, 916 BUS_DMASYNC_POSTREAD); 917 if (ahd->qoutfifo[ahd->qoutfifonext] != SCB_LIST_NULL_LE) 918 retval |= AHD_RUN_QOUTFIFO; 919 #ifdef AHD_TARGET_MODE 920 if ((ahd->flags & AHD_TARGETROLE) != 0 921 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 922 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 923 ahd->shared_data_dmamap, 924 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 925 /*len*/sizeof(struct target_cmd), 926 BUS_DMASYNC_POSTREAD); 927 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 928 retval |= AHD_RUN_TQINFIFO; 929 } 930 #endif 931 return (retval); 932 } 933 934 /* 935 * Catch an interrupt from the adapter 936 */ 937 static __inline void 938 ahd_intr(struct ahd_softc *ahd) 939 { 940 u_int intstat; 941 942 /* 943 * Instead of directly reading the interrupt status register, 944 * infer the cause of the interrupt by checking our in-core 945 * completion queues. This avoids a costly PCI bus read in 946 * most cases. 947 */ 948 if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 949 && (ahd_check_cmdcmpltqueues(ahd) != 0)) 950 intstat = CMDCMPLT; 951 else 952 intstat = ahd_inb(ahd, INTSTAT); 953 954 if (intstat & CMDCMPLT) { 955 ahd_outb(ahd, CLRINT, CLRCMDINT); 956 957 /* 958 * Ensure that the chip sees that we've cleared 959 * this interrupt before we walk the output fifo. 960 * Otherwise, we may, due to posted bus writes, 961 * clear the interrupt after we finish the scan, 962 * and after the sequencer has added new entries 963 * and asserted the interrupt again. 964 */ 965 ahd_flush_device_writes(ahd); 966 ahd_run_qoutfifo(ahd); 967 #ifdef AHD_TARGET_MODE 968 if ((ahd->flags & AHD_TARGETROLE) != 0) 969 ahd_run_tqinfifo(ahd, /*paused*/FALSE); 970 #endif 971 } 972 973 if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) 974 /* Hot eject */ 975 return; 976 977 if ((intstat & INT_PEND) == 0) 978 return; 979 980 if (intstat & HWERRINT) { 981 ahd_handle_hwerrint(ahd); 982 return; 983 } 984 985 if ((intstat & (PCIINT|SPLTINT)) != 0) { 986 ahd->bus_intr(ahd); 987 return; 988 } 989 990 if ((intstat & SEQINT) != 0) 991 ahd_handle_seqint(ahd, intstat); 992 993 if ((intstat & SCSIINT) != 0) 994 ahd_handle_scsiint(ahd, intstat); 995 } 996 997 #endif /* _AIC79XX_INLINE_H_ */ 998