int ahci_write_prdt(struct hba_memory *abar, struct hba_port *port, struct ahci_device *dev, int slot, int offset, int length, addr_t virt_buffer) { int num_entries = ((length-1) / PRDT_MAX_COUNT) + 1; struct hba_command_table *tbl = (struct hba_command_table *)(dev->ch[slot]); int i; struct hba_prdt_entry *prd; for(i=0;i<num_entries-1;i++) { /* TODO: do we need to do this? */ addr_t phys_buffer; mm_virtual_getmap(virt_buffer, &phys_buffer, 0); prd = &tbl->prdt_entries[i+offset]; prd->byte_count = PRDT_MAX_COUNT-1; prd->data_base_l = LOWER32(phys_buffer); prd->data_base_h = UPPER32(phys_buffer); prd->interrupt_on_complete=0; length -= PRDT_MAX_COUNT; virt_buffer += PRDT_MAX_COUNT; } addr_t phys_buffer; mm_virtual_getmap(virt_buffer, &phys_buffer, 0); prd = &tbl->prdt_entries[i+offset]; prd->byte_count = length-1; prd->data_base_l = LOWER32(phys_buffer); prd->data_base_h = UPPER32(phys_buffer); prd->interrupt_on_complete=0; return num_entries; }
/** Process pending wait requests */ void process_pending_wait(void) { task_exit_t texit; loop: list_foreach(pending_wait, cur) { pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link); unsigned long keys[2] = { LOWER32(pr->id), UPPER32(pr->id) }; link_t *link = hash_table_find(&task_hash_table, keys); if (!link) continue; hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link); if (!ht->finished) continue; if (!(pr->callid & IPC_CALLID_NOTIFICATION)) { texit = ht->have_rval ? TASK_EXIT_NORMAL : TASK_EXIT_UNEXPECTED; ipc_answer_2(pr->callid, EOK, texit, ht->retval); } hash_table_remove(&task_hash_table, keys, 2); list_remove(cur); free(pr); goto loop; }
static int answer_preprocess(call_t *answer, ipc_data_t *olddata) { int rc = EOK; if (!IPC_GET_RETVAL(answer->data)) { /* The recipient authorized the change of state. */ phone_t *recipient_phone; task_t *other_task_s; task_t *other_task_r; rc = phone_get(IPC_GET_ARG1(answer->data), &recipient_phone); if (rc != EOK) { IPC_SET_RETVAL(answer->data, ENOENT); return ENOENT; } mutex_lock(&recipient_phone->lock); if (recipient_phone->state != IPC_PHONE_CONNECTED) { mutex_unlock(&recipient_phone->lock); IPC_SET_RETVAL(answer->data, EINVAL); return EINVAL; } other_task_r = recipient_phone->callee->task; other_task_s = (task_t *) IPC_GET_ARG5(*olddata); /* * See if both the sender and the recipient meant the * same third party task. */ if (other_task_r != other_task_s) { IPC_SET_RETVAL(answer->data, EINVAL); rc = EINVAL; } else { rc = event_task_notify_5(other_task_r, EVENT_TASK_STATE_CHANGE, false, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(*olddata), IPC_GET_ARG3(*olddata), LOWER32(olddata->task_id), UPPER32(olddata->task_id)); IPC_SET_RETVAL(answer->data, rc); } mutex_unlock(&recipient_phone->lock); } return rc; }
/** Compare a key with hashed item. * * @param key Array of keys. * @param keys Must be less than or equal to 2. * @param item Pointer to a hash table item. * * @return Non-zero if the key matches the item, zero otherwise. * */ static int task_compare(unsigned long key[], hash_count_t keys, link_t *item) { assert(key); assert(keys <= 2); assert(item); hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link); if (keys == 2) return ((LOWER32(key[1]) == UPPER32(ht->id)) && (LOWER32(key[0]) == LOWER32(ht->id))); else return (LOWER32(key[0]) == LOWER32(ht->id)); }
int bd_read_blocks(bd_t *bd, aoff64_t ba, size_t cnt, void *data, size_t size) { async_exch_t *exch = async_exchange_begin(bd->sess); ipc_call_t answer; aid_t req = async_send_3(exch, BD_READ_BLOCKS, LOWER32(ba), UPPER32(ba), cnt, &answer); int rc = async_data_read_start(exch, data, size); async_exchange_end(exch); if (rc != EOK) { async_forget(req); return rc; } sysarg_t retval; async_wait_for(req, &retval); if (retval != EOK) return retval; return EOK; }
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { void *fs_va = NULL; ipc_callid_t callid; ipc_call_t call; sysarg_t method; size_t comm_size; unsigned int flags; int retval; uint64_t ba; size_t cnt; /* Answer the IPC_M_CONNECT_ME_TO call. */ async_answer_0(iid, EOK); if (!async_share_out_receive(&callid, &comm_size, &flags)) { async_answer_0(callid, EHANGUP); return; } (void) async_share_out_finalize(callid, &fs_va); if (fs_va == AS_MAP_FAILED) { async_answer_0(callid, EHANGUP); return; } while (true) { callid = async_get_call(&call); method = IPC_GET_IMETHOD(call); if (!method) { /* The other side has hung up. */ async_answer_0(callid, EOK); return; } switch (method) { case BD_READ_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_read_blocks(ba, cnt, fs_va); break; case BD_WRITE_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_write_blocks(ba, cnt, fs_va); break; case BD_GET_BLOCK_SIZE: async_answer_1(callid, EOK, block_size); continue; case BD_GET_NUM_BLOCKS: async_answer_2(callid, EOK, LOWER32(num_blocks), UPPER32(num_blocks)); continue; default: retval = EINVAL; break; } async_answer_0(callid, retval); } }