📄 i2o_core.c
字号:
*/int i2o_lct_notify(struct i2o_controller *c){ u32 msg[8]; msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2] = core_context; msg[3] = 0xDEADBEEF; msg[4] = 0xFFFFFFFF; /* All devices */ msg[5] = c->dlct->change_ind+1; /* Next change */ msg[6] = 0xD0000000|8192; msg[7] = virt_to_bus(c->dlct); return i2o_post_this(c, msg, sizeof(msg));} /* * Bring a controller online into OPERATIONAL state. */int i2o_online_controller(struct i2o_controller *iop){ if (i2o_systab_send(iop) < 0) return -1; /* In READY state */ dprintk(KERN_INFO "%s: Attempting to enable...\n", iop->name); if (i2o_enable_controller(iop) < 0) return -1; /* In OPERATIONAL state */ dprintk(KERN_INFO "%s: Attempting to get/parse lct...\n", iop->name); if (i2o_lct_get(iop) < 0) return -1; return 0;}/* * Build system table * * The system table contains information about all the IOPs in the * system (duh) and is used by the Executives on the IOPs to establish * peer2peer connections. We're not supporting peer2peer at the moment, * but this will be needed down the road for things like lan2lan forwarding. */static int i2o_build_sys_table(void){ struct i2o_controller *iop = NULL; struct i2o_controller *niop = NULL; int count = 0; sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs (i2o_num_controllers) * sizeof(struct i2o_sys_tbl_entry); if(sys_tbl) kfree(sys_tbl); sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL); if(!sys_tbl) { printk(KERN_CRIT "SysTab Set failed. Out of memory.\n"); return -ENOMEM; } memset((void*)sys_tbl, 0, sys_tbl_len); sys_tbl->num_entries = i2o_num_controllers; sys_tbl->version = I2OVERSION; /* TODO: Version 2.0 */ sys_tbl->change_ind = sys_tbl_ind++; for(iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; /* * Get updated IOP state so we have the latest information * * We should delete the controller at this point if it * doesn't respond since if it's not on the system table * it is techninically not part of the I2O subsy遲em... */ if(i2o_status_get(iop)) { printk(KERN_ERR "%s: Deleting b/c could not get status while" "attempting to build system table\n", iop->name); i2o_delete_controller(iop); sys_tbl->num_entries--; continue; // try the next one } sys_tbl->iops[count].org_id = iop->status_block->org_id; sys_tbl->iops[count].iop_id = iop->unit + 2; sys_tbl->iops[count].seg_num = 0; sys_tbl->iops[count].i2o_version = iop->status_block->i2o_version; sys_tbl->iops[count].iop_state = iop->status_block->iop_state; sys_tbl->iops[count].msg_type = iop->status_block->msg_type; sys_tbl->iops[count].frame_size = iop->status_block->inbound_frame_size; sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? sys_tbl->iops[count].iop_capabilities = iop->status_block->iop_capabilities; sys_tbl->iops[count].inbound_low = (u32)virt_to_bus(iop->post_port); sys_tbl->iops[count].inbound_high = 0; // TODO: 64-bit support count++; }#ifdef DRIVERDEBUG{ u32 *table; table = (u32*)sys_tbl; for(count = 0; count < (sys_tbl_len >>2); count++) printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);}#endif return 0;}/* * Run time support routines */ /* * Generic "post and forget" helpers. This is less efficient - we do * a memcpy for example that isnt strictly needed, but for most uses * this is simply not worth optimising */int i2o_post_this(struct i2o_controller *c, u32 *data, int len){ u32 m; u32 *msg; unsigned long t=jiffies; do { mb(); m = I2O_POST_READ32(c); } while(m==0xFFFFFFFF && (jiffies-t)<HZ); if(m==0xFFFFFFFF) { printk(KERN_ERR "%s: Timeout waiting for message frame!\n", c->name); return -ETIMEDOUT; } msg = (u32 *)(c->mem_offset + m); memcpy_toio(msg, data, len); i2o_post_message(c,m); return 0;}/* * This core API allows an OSM to post a message and then be told whether * or not the system received a successful reply. It is useful when * the OSM does not want to know the exact 3 */int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout){ DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); int status = 0; int flags = 0; struct i2o_post_wait_data *p1, *p2; struct i2o_post_wait_data *wait_data = kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL); if(!wait_data) return -ENOMEM; /* * The spin locking is needed to keep anyone from playing * with the queue pointers and id while we do the same */ spin_lock_irqsave(&post_wait_lock, flags); wait_data->next = post_wait_queue; post_wait_queue = wait_data; wait_data->id = (++post_wait_id) & 0x7fff; spin_unlock_irqrestore(&post_wait_lock, flags); wait_data->wq = &wq_i2o_post; wait_data->status = -ETIMEDOUT; msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16); if ((status = i2o_post_this(c, msg, len))==0) { interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout); status = wait_data->status; } #ifdef DRIVERDEBUG if(status == -ETIMEDOUT) printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name);#endif /* * Remove the entry from the queue. * Since i2o_post_wait() may have been called again by * a different thread while we were waiting for this * instance to complete, we're not guaranteed that * this entry is at the head of the queue anymore, so * we need to search for it, find it, and delete it. */ p2 = NULL; spin_lock_irqsave(&post_wait_lock, flags); for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) { if(p1 == wait_data) { if(p2) p2->next = p1->next; else post_wait_queue = p1->next; break; } } spin_unlock_irqrestore(&post_wait_lock, flags); kfree(wait_data); return status;}/* * i2o_post_wait is completed and we want to wake up the * sleeping proccess. Called by core's reply handler. */static void i2o_post_wait_complete(u32 context, int status){ struct i2o_post_wait_data *p1 = NULL; /* * We need to search through the post_wait * queue to see if the given message is still * outstanding. If not, it means that the IOP * took longer to respond to the message than we * had allowed and timer has already expired. * Not much we can do about that except log * it for debug purposes, increase timeout, and recompile * * Lock needed to keep anyone from moving queue pointers * around while we're looking through them. */ spin_lock(&post_wait_lock); for(p1 = post_wait_queue; p1; p1 = p1->next) { if(p1->id == ((context >> 16) & 0x7fff)) { p1->status = status; wake_up_interruptible(p1->wq); spin_unlock(&post_wait_lock); return; } } spin_unlock(&post_wait_lock); printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n");}/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET * * This function can be used for all UtilParamsGet/Set operations. * The OperationList is given in oplist-buffer, * and results are returned in reslist-buffer. * Note that the minimum sized reslist is 8 bytes and contains * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. */int i2o_issue_params(int cmd, struct i2o_controller *iop, int tid, void *oplist, int oplen, void *reslist, int reslen){ u32 msg[9]; u8 *res = (u8 *)reslist; u32 *res32 = (u32*)reslist; u32 *restmp = (u32*)reslist; int len = 0; int i = 0; int wait_status; msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; msg[1] = cmd << 24 | HOST_TID << 12 | tid; msg[3] = 0; msg[4] = 0; msg[5] = 0x54000000 | oplen; /* OperationList */ msg[6] = virt_to_bus(oplist); msg[7] = 0xD0000000 | reslen; /* ResultList */ msg[8] = virt_to_bus(reslist); if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10))) return wait_status; /* -DetailedStatus */ /* * Calculate number of bytes of Result LIST * We need to loop through each Result BLOCK and grab the length */ restmp = res32 + 1; len = 1; for(i = 0; i < (res32[0]&0X0000FFFF); i++) { if(restmp[0]&0x00FF0000) /* BlockStatus != SUCCESS */ { printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, " "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" : "PARAMS_GET", res32[1]>>24, (res32[1]>>16)&0xFF, res32[1]&0xFFFF); /* * If this is the only request,than we return an error */ if((res32[0]&0x0000FFFF) == 1) return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ } len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ } return (len << 2); /* bytes used by result list */}/* * Query one scalar group value or a whole scalar group. */ int i2o_query_scalar(struct i2o_controller *iop, int tid, int group, int field, void *buf, int buflen){ u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; u8 resblk[8+buflen]; /* 8 bytes for header */ int size; if (field == -1) /* whole group */ opblk[4] = -1; size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk)); if (size < 0) return size; memcpy(buf, resblk+8, buflen); /* cut off header */ return size;}/* * Set a scalar group value or a whole group. */int i2o_set_scalar(struct i2o_controller *iop, int tid, int group, int field, void *buf, int buflen){ u16 *opblk; u8 resblk[8+buflen]; /* 8 bytes for header */ int size; opblk = kmalloc(buflen+64, GFP_KERNEL); if (opblk == NULL) { printk(KERN_ERR "i2o: no memory for operation buffer.\n"); return -ENOMEM; } opblk[0] = 1; /* operation count */ opblk[1] = 0; /* pad */ opblk[2] = I2O_PARAMS_FIELD_SET; opblk[3] = group; if(field == -1) { /* whole group */ opblk[4] = -1; memcpy(opblk+5, buf, buflen); } else /* single field */ { opblk[4] = 1; opblk[5] = field; memcpy(opblk+6, buf, buflen); } size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, opblk, 12+buflen, resblk, sizeof(resblk)); kfree(opblk); return size;}/* * if oper == I2O_PARAMS_TABLE_GET, get from all rows * if fieldcount == -1 return all fields * ibuf and ibuflen are unused (use NULL, 0) * else return specific fields * ibuf contains fieldindexes * * if oper == I2O_PARAMS_LIST_GET, get from specific rows * if fieldcount == -1 return all fields * ibuf contains rowcount, keyvalues * else return specific fields * fieldcount is # of fieldindexes * ibuf contains fieldindexes, rowcount, keyvalues * * You could also use directly function i2o_issue_params(). */int i2o_query_table(int oper, struct i2o_controller *iop, int tid, int group, int fieldcount, void *ibuf, int ibuflen, void *resblk, int reslen) { u16 *opblk; int size; opblk = kmalloc(10 + ibuflen, GFP_KERNEL); if (opblk == NULL) { printk(KERN_ERR "i2o: no memory for query buffer.\n"); return -ENOMEM; } opblk[0] = 1; /* operation count */ opblk[1] = 0; /* pad */ opblk[2] = oper; opblk[3] = group; opblk[4] = fieldcount; memcpy(opblk+5, ibuf, ibuflen); /* other params */ size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET,iop, tid, opblk, 10+ibuflen, resblk, reslen); kfree(opblk); return size;}/* * Clear table group, i.e. delete all rows. */int i2o_clear_table(struct i2o_controller *iop, int tid, int group){ u16 opblk[] = { 1, 0, I2O_PARAMS_TABLE_CLEAR, group }; u8 resblk[32]; /* min 8 bytes for result header */ return i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, opblk, sizeof(opblk), resblk, sizeof(resblk));}/* * Add a new row into a table group. * * if fieldcount==-1 then we add whole rows * buf contains rowcount, keyvalues * else just specific fields are given, rest use defaults * buf contains fieldindexes, rowcount, keyvalues */ int i2o_row_add_table(struct i2o_controller *iop, int tid, int group, int fieldcount, void *buf, int buflen){ u16 *opblk; u8 resblk[32]; /* min 8 bytes for header */ int size; opblk = kmalloc(buflen+64, GFP_KERNEL); if (opblk == NULL) { printk(KERN_ERR "i2o: no memory for operation buffer.\n"); return -ENOMEM; } opblk[0] = 1; /* operation count */ opblk[1] = 0; /* pad */ opblk[2] = I2O_PARAMS_ROW_ADD; opblk[3] = group; opblk[4] = fieldcount; memcpy(opblk+5, buf, buflen); size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_SET, iop, tid, opblk, 10+buflen, resblk, sizeof(resblk)); kfree(opblk); return size;}/* * Used for error reporting/debugging purposes. * Following fail status are common to all classes. * The preserved message must be handled in the reply handler. */void i2o_report_fail_status(u8 req_status, u32* msg){ static char *FAIL_STATUS[] = { "0x80", /* not used */ "SERVICE_SUSPENDED", /* 0x81 */ "SERVICE_TERMINATED", /* 0x82 */ "CONGESTION", "FAILURE", "STATE_ERROR", "TIME_OUT", "ROUTING_FAILURE", "INVALID_VERSION", "INVALID_OFFSET", "INVALID_MSG_FLAGS", "FRAME_TOO_SMALL", "FRAME_TOO_LARGE", "INVALID_TARGET_ID", "INVALID_INITIATOR_ID", "INVALID_INITIATOR_CONTEX", /* 0x8F */ "UNKNOWN_FAILURE" /* 0xFF */ }; if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE) printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status); else printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]); /* Dump some details */ printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n", (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF); printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n", (msg[4] >> 8) & 0xFF, msg[4] & 0xFF); printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n", msg[5] >> 16, msg[5] & 0xFFF); printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF); if (msg[4] & (1<<16)) printk("(FormatError), " "this msg can never be delivered/processed.\n"); if (msg[4] & (1<<17)) printk("(PathError), " "this msg can no longer be delivered/processed.\n"); if (msg[4] & (1<<18)) printk("(PathState), " "the system state does not allow delivery.\n"); if (msg[4] & (1<<19)) printk("(Congestion), resources temporarily not available;" "do not retry immediately.\n");}/* * Used for error reporting/debugging purposes. * Following reply status are common to all classes. */void i2o_report_common_status(u8 req_status){ static char *REPLY_STATUS[] = { "SUCCESS", "ABORT_DIRTY", "ABORT_NO_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -