int rwlock_release( struct rwlock *rw ) { acquire_spinlock( &(rw->spinlock) ); if ( rw->num_writers != 0 ) { rw->write_request = 0; rw->num_writers = 0; } else { rw->num_readers -= 1; } release_spinlock( &(rw->spinlock) ); return 0; }
static status_t read_hook (void* cookie, off_t position, void *buf, size_t* num_bytes) { dp83815_properties_t *data = cookie; cpu_status former; descriptor_t* desc; size_t length = 0; TRACE(( kDevName ": read_hook()\n" )); //if( !data->nonblocking ) acquire_sem_etc( data->Rx.Sem, 1, B_CAN_INTERRUPT|data->blockFlag, NONBLOCK_WAIT ); { former = disable_interrupts(); acquire_spinlock(&data->Rx.Lock); desc = data->Rx.Curr; data->Rx.Curr = desc->virt_next; release_spinlock(&data->Rx.Lock); restore_interrupts(former); } length= DESC_LENGTH&desc->cmd; if( desc->cmd & (DESC_RXA|DESC_RXO|DESC_LONG|DESC_RUNT|DESC_ISE|DESC_CRCE|DESC_FAE|DESC_LBP|DESC_COL) ) TRACE(( "desc cmd: %x\n", desc->cmd )); if( length < 64 ) { *num_bytes = 0; return B_ERROR; } if( *num_bytes < length ) length = *num_bytes; memcpy(buf, desc->virt_buff,length); desc->cmd = DESC_LENGTH&MAX_PACKET_SIZE; *num_bytes = length; atomic_add(&data->stats.rx_att, 1); if( length == 0 ) return B_ERROR; return B_OK; }
int irq_ack( struct thread *t, int irq, int status ) { acquire_spinlock( &irq_lock ); dmesg("%!ACK with status %i for %i\n", status, irq ); if ( status == 0 ) { unmask_irq( irq ); release_spinlock( &irq_lock ); return 0; } dmesg("%!Unhandled IRQ %i\n", irq ); release_spinlock( &irq_lock ); return 0; }
up(sem_t &sem) { disable_interrupts(); acquire_spinlock(mu); sem->val++; if (not_empty(queue)) { // threads are waiting - wake one up other_thread = dequeue(queue); other_thread->state = READY; add_to_ready_queue(other_thread); } release_spinlock(mu); enable_interrupts(); }
int release_irq( struct thread *t, int irq ) { int ans = -1; if ( (irq < 0) || (irq >= IRQ_COUNT) ) return -1; acquire_spinlock( &irq_lock ); if ( handlers[irq] == t ) { handlers[irq] = NULL; if ( masked(irq) == 0 ) mask_irq( irq ); ans = 0; } release_spinlock( &irq_lock ); return ans; }
int destroy_global_semaphore( int pid, int sem_id ) { struct sem_link *sl = NULL; struct sem_link *tmp = NULL; struct process *proc = NULL; struct thread *tr = NULL; if ( sem_id < 0 ) return -1; if ( sem_id >= GLOBAL_SEM_COUNT ) return -1; acquire_spinlock( & global_sems_lock ); if ( ( global_sems[ sem_id ].sem_id != sem_id ) || ( global_sems[ sem_id ].pid != pid ) ) { // Invalid or not allowed. release_spinlock( & global_sems_lock ); return -1; } // Tell the waiting guys to go away. sl = global_sems[ sem_id ].waiting_list; while ( sl != NULL ) { tmp = sl; proc = checkout_process( sl->pid, WRITER ); if ( proc != NULL ) { tr = find_thread_with_id( proc, sl->tid ); if ( tr != NULL ) set_thread_state( tr, THREAD_RUNNING ); commit_process( proc ); } sl = sl->next; free( tmp ); } global_sems[ sem_id ].waiting_list = NULL; global_sems[ sem_id ].sem_id = -1; // DELETED! release_spinlock( & global_sems_lock ); return 0; }
void arch_debug_serial_puts(const char *s) { cpu_status state = 0; if (!debug_debugger_running()) { state = disable_interrupts(); acquire_spinlock(&sSerialOutputSpinlock); } while (*s != '\0') { _arch_debug_serial_putchar(*s); s++; } if (!debug_debugger_running()) { release_spinlock(&sSerialOutputSpinlock); restore_interrupts(state); } }
int rwlock_get_write_access( struct rwlock *rw ) { while ( 1==1 ) { acquire_spinlock( &(rw->spinlock) ); if ( (rw->num_readers == 0) && (rw->num_writers == 0) ) { rw->num_writers += 1; release_spinlock( &(rw->spinlock) ); break; } else rw->write_request = 1; release_spinlock( &(rw->spinlock) ); } return 0; }
static status_t write_hook (void* cookie, off_t position, const void* buffer, size_t* num_bytes) { dp83815_properties_t *data = cookie; cpu_status former; descriptor_t* desc; TRACE(( kDevName " write_hook()\n" )); acquire_sem( data->lock ); acquire_sem_etc( data->Tx.Sem, 1, B_CAN_INTERRUPT|data->blockFlag, NONBLOCK_WAIT ); { former = disable_interrupts(); acquire_spinlock(&data->Tx.Lock); desc = data->Tx.Curr; data->Tx.Curr = desc->virt_next; release_spinlock(&data->Tx.Lock); restore_interrupts(former); } if ( *num_bytes > MAX_PACKET_SIZE ) { /* if needed */ TRACE(( "Had to truncate the packet from %d to %d\n", *num_bytes, MAX_PACKET_SIZE)); *num_bytes = MAX_PACKET_SIZE; /* truncate the packet */ } while( desc->cmd&DESC_OWN ) { /* make sure a buffer is available */ TRACE(( "spinning in the write hook\n")); spin(1000); /* wait a while if not */ } memcpy(desc->virt_buff, buffer, *num_bytes); /* now copy the data */ desc->cmd = DESC_OWN|*num_bytes; /* update the cmd bits */ write32(REG_CR, CR_TXE); /* tell the card to start tx */ atomic_add(&data->stats.tx_att, 1); release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE ); return B_OK; }
SORAAPI insert_thread_safe_enlist_tail(struct thread_safe_enlist* tslist, void* value, char lock) { KIRQL irql; acquire_spinlock(lock, tslist->m_sync, irql); struct LIST_ENTRY_EX* entry; entry = (struct LIST_ENTRY_EX*)ExAllocateFromNPagedLookasideList (&tslist->m_lookaside); entry->m_value = value; InsertTailList(&tslist->m_head.m_entry, &entry->m_entry); InterlockedIncrement(&tslist->m_count); release_spinlock(lock, tslist->m_sync, irql); return entry; }
LM_STATUS MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice) { struct be_b57_dev *dev = (struct be_b57_dev *)pDevice; PLM_PACKET pPacket; while (1) { pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketReceivedQ.Container); if (pPacket == 0) break; acquire_spinlock(&dev->lock); release_sem_etc(dev->packet_release_sem, 1, B_DO_NOT_RESCHEDULE); release_spinlock(&dev->lock); QQ_PushTail(&dev->RxPacketReadQ.Container, pPacket); } return LM_STATUS_SUCCESS; }
static status_t b57_write(void *cookie,off_t pos,const void *data,size_t *numBytes) { struct be_b57_dev *pUmDevice = (struct be_b57_dev *)cookie; PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; PLM_PACKET pPacket; struct B_UM_PACKET *pUmPacket; cpu_status cpu; /*if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || !pDevice->InitDone) { return ENETDOWN; }*/ pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->TxPacketFreeQ.Container); if (pPacket == 0) return B_ERROR; pUmPacket = (struct B_UM_PACKET *)pPacket; pUmPacket->data = chunk_pool_get(); memcpy(pUmPacket->data,data,*numBytes); /* no guarantee data is contiguous, so we have to copy */ pPacket->PacketSize = pUmPacket->size = *numBytes; pPacket->u.Tx.FragCount = 1; pPacket->Flags = 0; tx_cleanup_thread(pUmDevice); cpu = disable_interrupts(); acquire_spinlock(&pUmDevice->lock); LM_SendPacket(pDevice, pPacket); release_spinlock(&pUmDevice->lock); restore_interrupts(cpu); return B_OK; }
void rtl8169_xmit(rtl8169 *r, const char *ptr, ssize_t len) { //int i; #if debug_level_flow >= 3 dprintf("rtl8169_xmit dumping packet:"); hexdump(ptr, len, 0, 0); #endif restart: hal_sem_acquire(&r->tx_sem); hal_mutex_lock(&r->lock); int_disable_interrupts(); acquire_spinlock(&r->reg_spinlock); /* look at the descriptor pointed to by tx_idx_free */ if (r->txdesc[r->tx_idx_free].flags & RTL_DESC_OWN) { /* card owns this one, wait and try again later */ release_spinlock(&r->reg_spinlock); int_restore_interrupts(); mutex_unlock(&r->lock); // sem_release(r->tx_sem, 1); goto restart; } /* queue it up */ memcpy(TXBUF(r, r->tx_idx_free), ptr, len); if (len < 64) len = 64; r->txdesc[r->tx_idx_free].frame_len = len; r->txdesc[r->tx_idx_free].flags = (r->txdesc[r->tx_idx_free].flags & RTL_DESC_EOR) | RTL_DESC_FS | RTL_DESC_LS | RTL_DESC_OWN; inc_tx_idx_free(r); RTL_WRITE_8(r, REG_TPPOLL, (1<<6)); // something is on the normal queue release_spinlock(&r->reg_spinlock); int_restore_interrupts(); mutex_unlock(&r->lock); }
int64 _user_atomic_get64(vint64 *value) { cpu_status status; int64 oldValue; if (!IS_USER_ADDRESS(value) || lock_memory((void *)value, 8, B_READ_DEVICE) != B_OK) goto access_violation; status = disable_interrupts(); acquire_spinlock(&atomic_lock); oldValue = *value; release_spinlock(&atomic_lock); restore_interrupts(status); unlock_memory((void *)value, 8, B_READ_DEVICE); return oldValue; access_violation: // XXX kill application return -1; }
static int32 sis900_rxInterrupt(struct sis_info *info) { int32 handled = B_UNHANDLED_INTERRUPT; int16 releaseRxSem = 0; int16 limit; acquire_spinlock(&info->rxSpinlock); HACK(spin(10000)); // check for packet ownership for (limit = info->rxFree; limit > 0; limit--) { if (!(info->rxDescriptor[info->rxInterruptIndex].status & SiS900_DESCR_OWN)) { // if (limit == info->rxFree) // { //dprintf("here!\n"); // limit++; // continue; // } break; } //dprintf("received frame %d!\n",info->rxInterruptIndex); releaseRxSem++; info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK; info->rxFree--; } release_spinlock(&info->rxSpinlock); // reenable rx queue write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE); if (releaseRxSem) { release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } return handled; }
status_t AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout) { status_t result = acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout); if (result < B_OK) { cpu_status cpu = disable_interrupts(); acquire_spinlock(&fSpinlock); fCommandsActive &= ~1; release_spinlock(&fSpinlock); restore_interrupts(cpu); result = B_TIMED_OUT; } else if (fError) { *tfd = fRegs->tfd; result = B_ERROR; fError = false; } else { *tfd = fRegs->tfd; } return result; }
int request_irq( struct thread *t, int irq ) { int ans = -1; if ( (irq < 0) || (irq >= IRQ_COUNT) ) return -1; acquire_spinlock( &irq_lock ); if ( handlers[irq] == NULL ) { handlers[irq] = t; t->state = THREAD_IRQ; if ( masked( irq ) != 0 ) unmask_irq( irq ); ans = 0; } release_spinlock( &irq_lock ); return ans; }
err_code resume_thread(thread_id id) { err_code err = ERR_NONE; CAST_TO_THREAD(thrd, id); acquire_spinlock(&inactive.lock, 0); if (thrd->state == THREAD_STATE_PAUSED) { if (thrd->next) thrd->next->prev = thrd->prev; if (thrd->prev) thrd->prev->next = thrd->next; if (inactive.tail == thrd) inactive.tail = thrd->next; inactive.total_threads--; thrd->real_priority = thrd->priority; thrd->quantum = 0; update_priority_quantum(thrd); struct cpu_task task = { .type = CPU_TASK_RESUME, .thread = thrd }; run_cpu_task(find_least_loaded_cpu(thrd->affinity), &task); } else
int aqueue_add( struct aqueue *aq, void* obj ) { struct aqueue_page *page = NULL; void* position; acquire_spinlock( &(aq->lock) ); int page_div = aq->last_position / aq->obj_count; int page_mod = aq->last_position % aq->obj_count; if ( (page_mod == 0) && (aq->pages <= page_div) ) { size_t size = sizeof(struct aqueue_page) + aq->obj_count * aq->obj_size; page = (struct aqueue_page*)kmalloc( size ); if ( page == NULL ) { release_spinlock( &(aq->lock) ); return -1; } page->next = NULL; aq->pages += 1; if ( aq->page == NULL ) aq->page = page; else aq->last_page->next = page; aq->last_page = page; } page = aq->last_page; position = page; position = position + sizeof( struct aqueue_page ) + aq->obj_size * page_mod; kmemcpy( position, obj, aq->obj_size ); release_spinlock( &(aq->lock) ); return 0; }
struct sem_t { spinlock mu; int val; thread *queue; } /* * down * * If semaphore value is positive, decrement it. * Otherwise, wait. * */ down(sem_t &sem) { while (1) { disable_interrupts(); acquire_spinlock(mu); if (sem->val > 0) { // Semaphore was available sem->val--; release_spinlock(mu); enable_interrupts(); return; } else { // Semaphore in use - go to sleep this_thread->state = WAITING; enqueue(queue,this_thread); release_spinlock(mu); enable_interrupts(); schedule(); // pick a READY thread to run // when schedule returns, this thread will be RUNNING } } // repeat }
int destroy_local_semaphore( struct process *proc, int sem_id ) { struct sem_link *sl = NULL; struct sem_link *tmp = NULL; struct thread *tr = NULL; if ( sem_id < 0 ) return -1; if ( sem_id >= LOCAL_SEM_COUNT ) return -1; acquire_spinlock( & (proc->sems_lock) ); if ( proc->sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & (proc->sems_lock) ); return -1; } // Tell the waiting guys to go away. sl = proc->sems[ sem_id ].waiting_list; while ( sl != NULL ) { tmp = sl; tr = find_thread_with_id( proc, sl->tid ); if ( tr != NULL ) set_thread_state( tr, THREAD_RUNNING ); sl = sl->next; free( tmp ); } proc->sems[ sem_id ].waiting_list = NULL; proc->sems[ sem_id ].sem_id = -1; // DELETED! release_spinlock( & (proc->sems_lock) ); return 0; }
char SORAAPI remove_thread_safe_enlist_entry(struct thread_safe_enlist* tslist, struct LIST_ENTRY_EX* entry, char lock) { KIRQL irql; acquire_spinlock(lock, tslist->m_sync, irql); if (IsListEmpty(&tslist->m_head.m_entry)) { release_spinlock(lock, tslist->m_sync, irql); return false; } RemoveEntryList(&entry->m_entry); InterlockedDecrement(&tslist->m_count); release_spinlock(lock, tslist->m_sync, irql); return true; }
void reschedule(void) { int hwthread = __builtin_nyuzi_read_control_reg(CR_CURRENT_THREAD); struct thread *old_thread; struct thread *next_thread; // Put current thread back on ready queue acquire_spinlock(&thread_q_lock); old_thread = cur_thread[hwthread]; enqueue_thread(&ready_q, old_thread); next_thread = dequeue_thread(&ready_q); if (old_thread != next_thread) { cur_thread[hwthread] = next_thread; context_switch(&old_thread->current_stack, next_thread->current_stack, next_thread->map->page_dir, next_thread->map->asid); } release_spinlock(&thread_q_lock); }
int aqueue_next( struct aqueue *aq, void* obj ) { void* position; acquire_spinlock( &(aq->lock) ); int page_div = aq->position / aq->obj_count; int page_mod = aq->position % aq->obj_count; assert( aq->position != aq->last_position ); while ( page_div > 0 ) { struct aqueue_page *tmp = aq->page; aq->page = aq->page->next; kfree( tmp ); assert( aq->page != NULL ); aq->last_position -= aq->obj_count; aq->position -= aq->obj_count; aq->pages -= 1; page_div -= 1; // Down one. } position = aq->page; position += sizeof( struct aqueue_page ) + aq->obj_size * page_mod; aq->position += 1; kmemcpy( obj, position, aq->obj_size ); release_spinlock( &(aq->lock) ); return 0; }
int signal_global_semaphore( struct thread* tr, int sem_id ) { struct sem_link *sl; struct process *proc; struct thread *target; acquire_spinlock( & global_sems_lock ); if ( global_sems[ sem_id ].sem_id != sem_id ) { release_spinlock( & global_sems_lock ); return -1; } global_sems[ sem_id ].count -= 1; // wake up any waiting threads sl = global_sems[ sem_id ].waiting_list; if ( sl != NULL ) { proc = checkout_process( sl->pid, WRITER ); if ( proc != NULL ) { target = find_thread_with_id( proc, sl->tid ); if ( target != NULL ) set_thread_state( target, THREAD_RUNNING ); commit_process( proc ); } global_sems[ sem_id ].waiting_list = sl->next; free( sl ); } release_spinlock( & ( global_sems_lock ) ); return 0; }
INTERNAL err_code __sleep_in_mutex(struct mutex *mutex) { struct __mutex_node *node = NULL; bool acquired; acquire_spinlock(&mutex->ilock, 0); acquired = acquire_spinlock_int(&mutex->mlock, 1); if (!acquired) { node = alloc_block(&mutex_node_pool); if (node) { node->next = NULL; node->id = get_thread(); if (mutex->head) mutex->head->next = node; mutex->head = node; if (!mutex->tail) mutex->tail = node; pause_this_thread(&mutex->ilock); } } if (!node) release_spinlock(&mutex->ilock); return (acquired || node) ? ERR_NONE : ERR_OUT_OF_MEMORY; }
int read_sdmmc_device(unsigned int block_address, void *ptr) { int result; int old_flags; old_flags = disable_interrupts(); acquire_spinlock(&sd_lock); result = send_sd_command(SD_CMD_READ_BLOCK, block_address); if (result != 0) return -1; for (int i = 0; i < BLOCK_SIZE; i++) ((char*) ptr)[i] = spi_transfer(0xff); // checksum (ignored) spi_transfer(0xff); spi_transfer(0xff); release_spinlock(&sd_lock); restore_interrupts(old_flags); return BLOCK_SIZE; }
void AHCIPort::Interrupt() { uint32 is = fRegs->is; fRegs->is = is; // clear interrupts if (is & PORT_INT_ERROR) { InterruptErrorHandler(is); return; } uint32 ci = fRegs->ci; RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08" B_PRIx32 ", " "is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", system_time(), find_thread(NULL), fIndex, fCommandsActive, is, ci); acquire_spinlock(&fSpinlock); if ((fCommandsActive & 1) && !(ci & 1)) { fCommandsActive &= ~1; release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE); } release_spinlock(&fSpinlock); }
timer_id create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags) { cpu_status cpu; timer_id id; if (func == 0) return -1; // Attention: flags are not real flags, as B_PERIODIC_TIMER is 3 cpu = disable_interrupts(); acquire_spinlock(&sTimerSpinlock); if (sTimerCount < MAX_TIMERS) { id = sTimerNextId; sTimerData[sTimerCount].id = id; sTimerData[sTimerCount].func = func; sTimerData[sTimerCount].cookie = cookie; sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval; sTimerData[sTimerCount].interval = interval; sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER; sTimerNextId++; sTimerCount++; } else { id = -1; } release_spinlock(&sTimerSpinlock); restore_interrupts(cpu); if (id != -1) release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); return id; }
static int32 scsi_int_dispatch(void *data) { Symbios *s = (Symbios *) data; int reselected = 0; uchar istat; if(s->reset) return B_UNHANDLED_INTERRUPT; acquire_spinlock(&(s->hwlock)); istat = inb(sym_istat); if(istat & sym_istat_dip){ uchar dstat = inb(sym_dstat); if(dstat & sym_dstat_sir){ /* Handle and interrupt from the SCRIPTS program */ uint32 status = HE(in32(sym_dsps)); // kprintf("<%02x>",status); switch(status){ case status_ready: kp("sym: ready\n"); break; case status_iocomplete: kp("sym: done %08x\n",s->active); if(s->active){ /* io is complete -- any more io is an error */ s->active->datain_phys = s->sram_phys + Ent_phase_dataerr; s->active->dataout_phys = s->sram_phys + Ent_phase_dataerr; } break; case status_reselected:{ uint32 id = inb(sym_ssid); if(id & sym_ssid_val) { s->active = &(s->targ[id & s->idmask]); kp("sym: resel %08x\n",s->active); if(s->active->status != status_waiting){ s->active = NULL; kprintf("symbios: bad reselect %ld\n",id & sym_ssid_encid); } else { reselected = 1; } } else { kprintf("symbios: invalid reselection!?\n"); } break; } case status_timeout: /* inform the unlucky party and dequeue it */ kp("sym: timeout %08lx\n",s->startqueue); if(s->startqueue){ s->startqueue->status = status_timeout; release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE); if(!(s->startqueue = s->startqueue->next)){ s->startqueuetail = NULL; } } break; case status_selected: /* selection succeeded. Remove from start queue and make active */ kp("sym: selected %08lx\n",s->startqueue); if(s->startqueue){ s->active = s->startqueue; s->active->status = status_active; if(!(s->startqueue = s->startqueue->next)){ s->startqueuetail = NULL; } } break; case status_syncin: setparams(s->active, s->active->priv->_syncmsg[1]*4, s->active->priv->_syncmsg[2], s->active->wide); break; case status_widein: setparams(s->active, s->active->period, s->active->offset, s->active->priv->_widemsg[1]); break; case status_ignore_residue: kprintf("ignore residue 0x%02x\n",s->active->priv->_extdmsg[0]); break; case status_disconnect: kp("sym: disc %08lx\n",s->active); /* device disconnected. make inactive */ if(s->active){ s->active->status = status_waiting; s->active = NULL; } break; case status_badmsg: kp("sym: badmsg %02x\n",s->active->priv->_recvmsg[0]); case status_complete: case status_badstatus: case status_overrun: case status_underrun: case status_badphase: case status_badextmsg: kp("sym: error %08lx / %02x\n",s->active,status); /* transaction completed successfully or in error. report our status. */ if(s->active){ s->active->status = status; release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE); s->active = NULL; } break; case status_selftest: /* signal a response to the selftest ... don't actually start up the SCRIPTS like we normally do */ s->status = OFFLINE; goto done; break; default: kp("sym: int 0x%08lx ...\n",status); } goto reschedule; } else { kprintf("symbios: weird error, dstat = %02x\n",dstat); } } if(istat & sym_istat_sip){ uchar sist0; sist0 = inb(sym_sist1); if(sist0 & sym_sist1_sbmc){ kprintf("sym: SBMC %02x!\n",inb(sym_stest4) & 0xc0); } if(sist0 & sym_sist1_sto){ /* select timeout */ kp("sym: Timeout %08lx\n",s->startqueue); /* inform the unlucky party and dequeue it */ if(s->startqueue){ s->startqueue->status = status_timeout; release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE); if(!(s->startqueue = s->startqueue->next)){ s->startqueuetail = NULL; } } else { kprintf("symbios: ghost target timed out\n"); } inb(sym_sist0); // apparently we MUST read sist0 as well goto reschedule; } sist0 = inb(sym_sist0) & 0x8f; if(sist0 && s->active){ if(sist0 & sym_sist0_ma){ /* phase mismatch -- we experienced a disconnect while in a DataIn or DataOut... gotta figure out how much we transferred, update the sgtable, take the FIFOs into account, etc (see 9-9 in Symbios PCI-SCSI Programming Guide) */ SymInd *t; uint32 dfifo_val, bytesleft, dbc; uint32 dsp = HE(in32(sym_dsp)); uint32 n = (dsp - s->active->table_phys) / 8 - 1; if((dsp < s->active->priv_phys) || (n > 129)) { /* we mismatched during some other phase ?! */ kprintf("Phase Mismatch (dsp = 0x%08lx)\n",dsp); goto reschedule; } t = &(s->active->priv->table[n]); #if 0 t->count = HE(t->count); t->address = HE(t->count); #endif /* dbc initially = table[n].count, counts down */ dbc = (uint32) HE(in32(sym_dbc)) & 0x00ffffffL; t->count &= 0xffffff; #if DEBUG_PM kprintf("PM(%s) dbc=0x%08x, n=%02d, a=0x%08x, l=0x%08x\n", s->active->inbound ? " in" : "out", dbc, n, t->address, t->count); #endif if(s->active->inbound){ /* data in is easy... flush happens automatically */ t->address += t->count - dbc; t->count = dbc; #if DEBUG_PM kprintf(" a=0x%08x, l=0x%08x\n", t->address, t->count); #endif s->active->datain_phys = s->active->table_phys + 8*(t->count ? n : n+1); t->count |= s->op_in; #if 0 t->count = LE(t->count); t->address = LE(t->address); #endif goto reschedule; } else { if(inb(sym_ctest5) & 0x20){ /* wide FIFO */ dfifo_val = ((inb(sym_ctest5) & 0x03) << 8) | inb(sym_dfifo); bytesleft = (dfifo_val - (dbc & 0x3ff)) & 0x3ff; } else { dfifo_val = (inb(sym_dfifo) & 0x7f); bytesleft = (dfifo_val - (dbc & 0x7f)) & 0x7f; } if(inb(sym_sstat0) & 0x20) bytesleft++; if(inb(sym_sstat2) & 0x20) bytesleft++; if(inb(sym_sstat0) & 0x40) bytesleft++; if(inb(sym_sstat2) & 0x40) bytesleft++; /* clear fifo */ outb(sym_ctest3, 0x04); t->address += t->count - dbc; t->count = dbc; /* adjust for data that didn't make it to the target */ t->address -= bytesleft; t->count += bytesleft; #if DEBUG_PM kprintf(" a=0x%08x, l=0x%08x\n", t->address, t->count); #endif s->active->dataout_phys = s->active->table_phys + 8*(t->count ? n : n+1); t->count |= s->op_out; #if 0 t->count = LE(t->count); t->address = LE(t->address); #endif spin(10); goto reschedule; } } if(sist0 & sym_sist0_udc){ kprintf("symbios: Unexpected Disconnect (dsp = 0x%08lx)\n", in32(sym_dsp)); } if(sist0 & sym_sist0_sge){ kprintf("symbios: SCSI Gross Error\n"); } if(sist0 & sym_sist0_rst){ kprintf("symbios: SCSI Reset\n"); } if(sist0 & sym_sist0_par){ kprintf("symbios: Parity Error\n"); } s->active->status = status_badphase; release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE); s->active = NULL; goto reschedule; } } else { /* nothing happened... must be somebody else's problem */ release_spinlock(&(s->hwlock)); return B_UNHANDLED_INTERRUPT; } reschedule: /* start the SCRIPTS processor at one of three places, depending on state ** ** 1. If there is an active transaction, insure that the script is patched ** correctly, the DSA is loaded, and start up at "switch". ** ** 2. If there is a transaction at the head of the startqueue, set the DSA ** and start up at "start" to try to select the target and start the ** transaction ** ** 3. If there is nothing else to do, go to "idle" and wait for signal or ** reselection */ if(s->active){ out32(sym_dsa, s->active->priv_phys + ADJUST_PRIV_TO_DSA); s->script[PATCH_DATAIN] = LE(s->active->datain_phys); s->script[PATCH_DATAOUT] = LE(s->active->dataout_phys); s->active->status = status_active; s->status = ACTIVE; if(reselected){ out32(sym_dsp, LE(s->sram_phys + Ent_switch_resel)); //kp("sym: restart @ %08x / reselected\n",Ent_switch_resel); } else { out32(sym_dsp, LE(s->sram_phys + Ent_switch)); //kp("sym: restart @ %08x / selected\n", Ent_switch); } } else { if(s->startqueue){ out32(sym_dsa, LE(s->startqueue->priv_phys + ADJUST_PRIV_TO_DSA)); s->startqueue->status = status_selecting; s->status = START; out32(sym_dsp, LE(s->sram_phys + Ent_start)); //kp("sym: restart @ %08x / started\n", Ent_start); } else { s->status = IDLE; out32(sym_dsp, LE(s->sram_phys + Ent_idle)); //kp("sym: restart @ %08x / idle\n", Ent_idle); } } done: release_spinlock(&(s->hwlock)); return B_HANDLED_INTERRUPT; }