1 /* 2 * Inline routines shareable across OS platforms. 3 * 4 * Copyright (c) 1994-2001 Justin T. Gibbs. 5 * Copyright (c) 2000-2002 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#34 $ 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 /* 316 * For Rev A short lun workaround. 317 */ 318 scb->hscb->pkt_long_lun[6] = scb->hscb->lun; 319 } else { 320 scb->hscb->task_attribute_nonpkt_tag = SCB_GET_TAG(scb); 321 } 322 323 if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 324 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 325 scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 326 ahd_htole32(scb->sense_busaddr); 327 } 328 329 static __inline void 330 ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 331 { 332 /* 333 * Copy the first SG into the "current" data ponter area. 334 */ 335 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 336 struct ahd_dma64_seg *sg; 337 338 sg = (struct ahd_dma64_seg *)scb->sg_list; 339 scb->hscb->dataptr = sg->addr; 340 scb->hscb->datacnt = sg->len; 341 } else { 342 struct ahd_dma_seg *sg; 343 344 sg = (struct ahd_dma_seg *)scb->sg_list; 345 scb->hscb->dataptr = sg->addr; 346 if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 347 uint64_t high_addr; 348 349 high_addr = ahd_le32toh(sg->len) & 0x7F000000; 350 scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 351 } 352 scb->hscb->datacnt = sg->len; 353 } 354 /* 355 * Note where to find the SG entries in bus space. 356 * We also set the full residual flag which the 357 * sequencer will clear as soon as a data transfer 358 * occurs. 359 */ 360 scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 361 } 362 363 static __inline void 364 ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 365 { 366 scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 367 scb->hscb->dataptr = 0; 368 scb->hscb->datacnt = 0; 369 } 370 371 /************************** Memory mapping routines ***************************/ 372 static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 373 static __inline void * 374 ahd_sg_bus_to_virt(struct ahd_softc *ahd, 375 struct scb *scb, 376 uint32_t sg_busaddr); 377 static __inline uint32_t 378 ahd_sg_virt_to_bus(struct ahd_softc *ahd, 379 struct scb *scb, 380 void *sg); 381 static __inline void ahd_sync_scb(struct ahd_softc *ahd, 382 struct scb *scb, int op); 383 static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 384 struct scb *scb, int op); 385 static __inline void ahd_sync_sense(struct ahd_softc *ahd, 386 struct scb *scb, int op); 387 static __inline uint32_t 388 ahd_targetcmd_offset(struct ahd_softc *ahd, 389 u_int index); 390 391 static __inline size_t 392 ahd_sg_size(struct ahd_softc *ahd) 393 { 394 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 395 return (sizeof(struct ahd_dma64_seg)); 396 return (sizeof(struct ahd_dma_seg)); 397 } 398 399 static __inline void * 400 ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 401 { 402 bus_addr_t sg_offset; 403 404 /* sg_list_phys points to entry 1, not 0 */ 405 sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 406 return ((uint8_t *)scb->sg_list + sg_offset); 407 } 408 409 static __inline uint32_t 410 ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 411 { 412 bus_addr_t sg_offset; 413 414 /* sg_list_phys points to entry 1, not 0 */ 415 sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 416 - ahd_sg_size(ahd); 417 418 return (scb->sg_list_busaddr + sg_offset); 419 } 420 421 static __inline void 422 ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 423 { 424 ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 425 scb->hscb_map->dmamap, 426 /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 427 /*len*/sizeof(*scb->hscb), op); 428 } 429 430 static __inline void 431 ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 432 { 433 if (scb->sg_count == 0) 434 return; 435 436 ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 437 scb->sg_map->dmamap, 438 /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 439 /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 440 } 441 442 static __inline void 443 ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 444 { 445 ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 446 scb->sense_map->dmamap, 447 /*offset*/scb->sense_busaddr, 448 /*len*/AHD_SENSE_BUFSIZE, op); 449 } 450 451 static __inline uint32_t 452 ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 453 { 454 return (((uint8_t *)&ahd->targetcmds[index]) 455 - (uint8_t *)ahd->qoutfifo); 456 } 457 458 /*********************** Miscelaneous Support Functions ***********************/ 459 static __inline void ahd_complete_scb(struct ahd_softc *ahd, 460 struct scb *scb); 461 static __inline void ahd_update_residual(struct ahd_softc *ahd, 462 struct scb *scb); 463 static __inline struct ahd_initiator_tinfo * 464 ahd_fetch_transinfo(struct ahd_softc *ahd, 465 char channel, u_int our_id, 466 u_int remote_id, 467 struct ahd_tmode_tstate **tstate); 468 static __inline uint16_t 469 ahd_inw(struct ahd_softc *ahd, u_int port); 470 static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 471 u_int value); 472 static __inline uint32_t 473 ahd_inl(struct ahd_softc *ahd, u_int port); 474 static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 475 uint32_t value); 476 static __inline uint64_t 477 ahd_inq(struct ahd_softc *ahd, u_int port); 478 static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 479 uint64_t value); 480 static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 481 static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 482 static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 483 static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 484 static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 485 static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 486 static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 487 static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 488 static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 489 static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 490 static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 491 static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 492 static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 493 static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 494 static __inline uint32_t 495 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 496 static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 497 struct scb *scb); 498 static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 499 static __inline uint8_t * 500 ahd_get_sense_buf(struct ahd_softc *ahd, 501 struct scb *scb); 502 static __inline uint32_t 503 ahd_get_sense_bufaddr(struct ahd_softc *ahd, 504 struct scb *scb); 505 506 static __inline void 507 ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 508 { 509 uint32_t sgptr; 510 511 sgptr = ahd_le32toh(scb->hscb->sgptr); 512 if ((sgptr & SG_STATUS_VALID) != 0) 513 ahd_handle_scb_status(ahd, scb); 514 else 515 ahd_done(ahd, scb); 516 } 517 518 /* 519 * Determine whether the sequencer reported a residual 520 * for this SCB/transaction. 521 */ 522 static __inline void 523 ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 524 { 525 uint32_t sgptr; 526 527 sgptr = ahd_le32toh(scb->hscb->sgptr); 528 if ((sgptr & SG_STATUS_VALID) != 0) 529 ahd_calc_residual(ahd, scb); 530 } 531 532 /* 533 * Return pointers to the transfer negotiation information 534 * for the specified our_id/remote_id pair. 535 */ 536 static __inline struct ahd_initiator_tinfo * 537 ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 538 u_int remote_id, struct ahd_tmode_tstate **tstate) 539 { 540 /* 541 * Transfer data structures are stored from the perspective 542 * of the target role. Since the parameters for a connection 543 * in the initiator role to a given target are the same as 544 * when the roles are reversed, we pretend we are the target. 545 */ 546 if (channel == 'B') 547 our_id += 8; 548 *tstate = ahd->enabled_targets[our_id]; 549 return (&(*tstate)->transinfo[remote_id]); 550 } 551 552 #define AHD_COPY_COL_IDX(dst, src) \ 553 do { \ 554 dst->hscb->scsiid = src->hscb->scsiid; \ 555 dst->hscb->lun = src->hscb->lun; \ 556 } while (0) 557 558 static __inline uint16_t 559 ahd_inw(struct ahd_softc *ahd, u_int port) 560 { 561 return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 562 } 563 564 static __inline void 565 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 566 { 567 ahd_outb(ahd, port, value & 0xFF); 568 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 569 } 570 571 static __inline uint32_t 572 ahd_inl(struct ahd_softc *ahd, u_int port) 573 { 574 return ((ahd_inb(ahd, port)) 575 | (ahd_inb(ahd, port+1) << 8) 576 | (ahd_inb(ahd, port+2) << 16) 577 | (ahd_inb(ahd, port+3) << 24)); 578 } 579 580 static __inline void 581 ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 582 { 583 ahd_outb(ahd, port, (value) & 0xFF); 584 ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 585 ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 586 ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 587 } 588 589 static __inline uint64_t 590 ahd_inq(struct ahd_softc *ahd, u_int port) 591 { 592 return ((ahd_inb(ahd, port)) 593 | (ahd_inb(ahd, port+1) << 8) 594 | (ahd_inb(ahd, port+2) << 16) 595 | (ahd_inb(ahd, port+3) << 24) 596 | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 597 | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 598 | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 599 | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 600 } 601 602 static __inline void 603 ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 604 { 605 ahd_outb(ahd, port, value & 0xFF); 606 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 607 ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 608 ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 609 ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 610 ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 611 ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 612 ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 613 } 614 615 static __inline u_int 616 ahd_get_scbptr(struct ahd_softc *ahd) 617 { 618 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 619 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 620 return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 621 } 622 623 static __inline void 624 ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 625 { 626 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 627 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 628 ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 629 ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 630 } 631 632 static __inline u_int 633 ahd_get_hnscb_qoff(struct ahd_softc *ahd) 634 { 635 return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 636 } 637 638 static __inline void 639 ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 640 { 641 ahd_outw_atomic(ahd, HNSCB_QOFF, value); 642 } 643 644 static __inline u_int 645 ahd_get_hescb_qoff(struct ahd_softc *ahd) 646 { 647 return (ahd_inb(ahd, HESCB_QOFF)); 648 } 649 650 static __inline void 651 ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 652 { 653 ahd_outb(ahd, HESCB_QOFF, value); 654 } 655 656 static __inline u_int 657 ahd_get_snscb_qoff(struct ahd_softc *ahd) 658 { 659 u_int oldvalue; 660 661 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 662 oldvalue = ahd_inw(ahd, SNSCB_QOFF); 663 ahd_outw(ahd, SNSCB_QOFF, oldvalue); 664 return (oldvalue); 665 } 666 667 static __inline void 668 ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 669 { 670 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 671 ahd_outw(ahd, SNSCB_QOFF, value); 672 } 673 674 static __inline u_int 675 ahd_get_sescb_qoff(struct ahd_softc *ahd) 676 { 677 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 678 return (ahd_inb(ahd, SESCB_QOFF)); 679 } 680 681 static __inline void 682 ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 683 { 684 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 685 ahd_outb(ahd, SESCB_QOFF, value); 686 } 687 688 static __inline u_int 689 ahd_get_sdscb_qoff(struct ahd_softc *ahd) 690 { 691 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 692 return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 693 } 694 695 static __inline void 696 ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 697 { 698 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 699 ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 700 ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 701 } 702 703 static __inline u_int 704 ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 705 { 706 u_int value; 707 708 /* 709 * Workaround PCI-X Rev A. hardware bug. 710 * After a host read of SCB memory, the chip 711 * may become confused into thinking prefetch 712 * was required. This starts the discard timer 713 * running and can cause an unexpected discard 714 * timer interrupt. The work around is to read 715 * a normal register prior to the exhaustion of 716 * the discard timer. The mode pointer register 717 * has no side effects and so serves well for 718 * this purpose. 719 * 720 * Razor #528 721 */ 722 value = ahd_inb(ahd, offset); 723 ahd_inb(ahd, MODE_PTR); 724 return (value); 725 } 726 727 static __inline u_int 728 ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 729 { 730 return (ahd_inb_scbram(ahd, offset) 731 | (ahd_inb_scbram(ahd, offset+1) << 8)); 732 } 733 734 static __inline uint32_t 735 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 736 { 737 return (ahd_inb_scbram(ahd, offset) 738 | (ahd_inb_scbram(ahd, offset+1) << 8) 739 | (ahd_inb_scbram(ahd, offset+2) << 16) 740 | (ahd_inb_scbram(ahd, offset+3) << 24)); 741 } 742 743 static __inline struct scb * 744 ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 745 { 746 struct scb* scb; 747 748 if (tag >= AHD_SCB_MAX) 749 return (NULL); 750 scb = ahd->scb_data.scbindex[tag]; 751 if (scb != NULL) 752 ahd_sync_scb(ahd, scb, 753 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 754 return (scb); 755 } 756 757 static __inline void 758 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 759 { 760 struct hardware_scb *q_hscb; 761 uint32_t saved_hscb_busaddr; 762 763 /* 764 * Our queuing method is a bit tricky. The card 765 * knows in advance which HSCB (by address) to download, 766 * and we can't disappoint it. To achieve this, the next 767 * HSCB to download is saved off in ahd->next_queued_hscb. 768 * When we are called to queue "an arbitrary scb", 769 * we copy the contents of the incoming HSCB to the one 770 * the sequencer knows about, swap HSCB pointers and 771 * finally assign the SCB to the tag indexed location 772 * in the scb_array. This makes sure that we can still 773 * locate the correct SCB by SCB_TAG. 774 */ 775 q_hscb = ahd->next_queued_hscb; 776 saved_hscb_busaddr = q_hscb->hscb_busaddr; 777 memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 778 q_hscb->hscb_busaddr = saved_hscb_busaddr; 779 q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 780 781 /* Now swap HSCB pointers. */ 782 ahd->next_queued_hscb = scb->hscb; 783 scb->hscb = q_hscb; 784 785 /* Now define the mapping from tag to SCB in the scbindex */ 786 /* XXX This should be constant now. Can we avoid the mapping? */ 787 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 788 } 789 790 /* 791 * Tell the sequencer about a new transaction to execute. 792 */ 793 static __inline void 794 ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 795 { 796 ahd_swap_with_next_hscb(ahd, scb); 797 798 if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 799 panic("Attempt to queue invalid SCB tag %x\n", 800 SCB_GET_TAG(scb)); 801 802 /* 803 * Keep a history of SCBs we've downloaded in the qinfifo. 804 */ 805 ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 806 ahd->qinfifonext++; 807 808 if (scb->sg_count != 0) 809 ahd_setup_data_scb(ahd, scb); 810 else 811 ahd_setup_noxfer_scb(ahd, scb); 812 ahd_setup_scb_common(ahd, scb); 813 814 /* 815 * Make sure our data is consistant from the 816 * perspective of the adapter. 817 */ 818 ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 819 820 #ifdef AHD_DEBUG 821 if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 822 printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 823 ahd_name(ahd), 824 SCB_GET_TAG(scb), scb->hscb->hscb_busaddr, 825 (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF), 826 (u_int)(scb->hscb->dataptr & 0xFFFFFFFF), 827 scb->hscb->datacnt); 828 } 829 #endif 830 /* Tell the adapter about the newly queued SCB */ 831 ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 832 } 833 834 static __inline uint8_t * 835 ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 836 { 837 return (scb->sense_data); 838 } 839 840 static __inline uint32_t 841 ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 842 { 843 return (scb->sense_busaddr); 844 } 845 846 /************************** Interrupt Processing ******************************/ 847 static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 848 static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 849 static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 850 static __inline void ahd_intr(struct ahd_softc *ahd); 851 852 static __inline void 853 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 854 { 855 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 856 /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); 857 } 858 859 static __inline void 860 ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 861 { 862 #ifdef AHD_TARGET_MODE 863 if ((ahd->flags & AHD_TARGETROLE) != 0) { 864 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 865 ahd->shared_data_dmamap, 866 ahd_targetcmd_offset(ahd, 0), 867 sizeof(struct target_cmd) * AHD_TMODE_CMDS, 868 op); 869 } 870 #endif 871 } 872 873 /* 874 * See if the firmware has posted any completed commands 875 * into our in-core command complete fifos. 876 */ 877 #define AHD_RUN_QOUTFIFO 0x1 878 #define AHD_RUN_TQINFIFO 0x2 879 static __inline u_int 880 ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 881 { 882 u_int retval; 883 884 retval = 0; 885 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 886 /*offset*/ahd->qoutfifonext, /*len*/2, 887 BUS_DMASYNC_POSTREAD); 888 if ((ahd->qoutfifo[ahd->qoutfifonext] 889 & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) 890 retval |= AHD_RUN_QOUTFIFO; 891 #ifdef AHD_TARGET_MODE 892 if ((ahd->flags & AHD_TARGETROLE) != 0 893 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 894 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 895 ahd->shared_data_dmamap, 896 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 897 /*len*/sizeof(struct target_cmd), 898 BUS_DMASYNC_POSTREAD); 899 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 900 retval |= AHD_RUN_TQINFIFO; 901 } 902 #endif 903 return (retval); 904 } 905 906 /* 907 * Catch an interrupt from the adapter 908 */ 909 static __inline void 910 ahd_intr(struct ahd_softc *ahd) 911 { 912 u_int intstat; 913 914 if ((ahd->pause & INTEN) == 0) { 915 /* 916 * Our interrupt is not enabled on the chip 917 * and may be disabled for re-entrancy reasons, 918 * so just return. This is likely just a shared 919 * interrupt. 920 */ 921 return; 922 } 923 924 /* 925 * Instead of directly reading the interrupt status register, 926 * infer the cause of the interrupt by checking our in-core 927 * completion queues. This avoids a costly PCI bus read in 928 * most cases. 929 */ 930 if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 931 && (ahd_check_cmdcmpltqueues(ahd) != 0)) 932 intstat = CMDCMPLT; 933 else 934 intstat = ahd_inb(ahd, INTSTAT); 935 936 if (intstat & CMDCMPLT) { 937 ahd_outb(ahd, CLRINT, CLRCMDINT); 938 939 /* 940 * Ensure that the chip sees that we've cleared 941 * this interrupt before we walk the output fifo. 942 * Otherwise, we may, due to posted bus writes, 943 * clear the interrupt after we finish the scan, 944 * and after the sequencer has added new entries 945 * and asserted the interrupt again. 946 */ 947 ahd_flush_device_writes(ahd); 948 ahd_run_qoutfifo(ahd); 949 #ifdef AHD_TARGET_MODE 950 if ((ahd->flags & AHD_TARGETROLE) != 0) 951 ahd_run_tqinfifo(ahd, /*paused*/FALSE); 952 #endif 953 } 954 955 if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) 956 /* Hot eject */ 957 return; 958 959 if ((intstat & INT_PEND) == 0) 960 return; 961 962 if (intstat & HWERRINT) { 963 ahd_handle_hwerrint(ahd); 964 return; 965 } 966 967 if ((intstat & (PCIINT|SPLTINT)) != 0) { 968 ahd->bus_intr(ahd); 969 return; 970 } 971 972 if ((intstat & SEQINT) != 0) 973 ahd_handle_seqint(ahd, intstat); 974 975 if ((intstat & SCSIINT) != 0) 976 ahd_handle_scsiint(ahd, intstat); 977 } 978 979 #endif /* _AIC79XX_INLINE_H_ */ 980