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