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