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