📄 ibmmca.c
字号:
return; } } last_scsi_command(ihost_index)[ldn] = NO_SCSI; last_scsi_type(ihost_index)[ldn] = 0; cmd = ld(ihost_index)[ldn].cmd; ld(ihost_index)[ldn].cmd = NULL;#ifdef IM_DEBUG_TIMEOUT if (cmd) { if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN)) { printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->lun); return; } }#endif /*if no command structure, just return, else clear cmd */ if (!cmd) return;#ifdef IM_DEBUG_INT printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(ihost_index)[ldn].tsb.dev_status, ld(ihost_index)[ldn].tsb.cmd_status, ld(ihost_index)[ldn].tsb.dev_error, ld(ihost_index)[ldn].tsb.cmd_error);#endif /*if this is end of media read/write, may turn off PS/2 disk led */ if ((ld(ihost_index)[ldn].device_type!=TYPE_NO_LUN)&& (ld(ihost_index)[ldn].device_type!=TYPE_NO_DEVICE)) { /* only access this, if there was a valid device addressed */ if (--disk_rw_in_progress == 0) PS2_DISK_LED_OFF (); } /* IBM describes the status-mask to be 0x1e, but this is not conform * with SCSI-definition, I suppose, the reason for it is that IBM * adapters do not support CMD_TERMINATED, TASK_SET_FULL and * ACA_ACTIVE as returning statusbyte information. (ML) */ if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { cmd->result = (unsigned char)(ld(ihost_index)[ldn].tsb.dev_status & 0x1e); IBM_DS(ihost_index).total_errors++; } else cmd->result = 0; /* write device status into cmd->result, and call done function */ if (lastSCSI == NO_SCSI) { /* unexpected interrupt :-( */ cmd->result |= DID_BAD_INTR << 16; printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n"); } else /* things went right :-) */ cmd->result |= DID_OK << 16; if (cmd->scsi_done) (cmd->scsi_done)(cmd); return;}static void issue_cmd (int host_index, unsigned long cmd_reg, unsigned char attn_reg){ unsigned long flags; /* must wait for attention reg not busy */ while (1) { IBMLOCK if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY)) break; IBMUNLOCK } /* write registers and enable system interrupts */ outl (cmd_reg, IM_CMD_REG(host_index)); outb (attn_reg, IM_ATTN_REG(host_index)); IBMUNLOCK return;}static void internal_done (Scsi_Cmnd * cmd){ cmd->SCp.Status++; return;}/* SCSI-SCB-command for device_inquiry */static int device_inquiry(int host_index, int ldn){ int retr; struct im_scb *scb; struct im_tsb *tsb; unsigned char *buf; scb = &(ld(host_index)[ldn].scb); tsb = &(ld(host_index)[ldn].tsb); buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); ld(host_index)[ldn].tsb.dev_status = 0; /* prepare statusblock */ for (retr=0; retr<3; retr++) { /* fill scb with inquiry command */ scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT; scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD; last_scsi_type(host_index)[ldn] = IM_SCB; scb->sys_buf_adr = virt_to_bus(buf); scb->sys_buf_length = 255; /* maximum bufferlength gives max info */ scb->tsb_adr = virt_to_bus(tsb); /* issue scb to passed ldn, and busy wait for interrupt */ got_interrupt(host_index) = 0; issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); while (!got_interrupt(host_index)) barrier (); /*if command succesful, break */ if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) return 1; } /*if all three retries failed, return "no device at this ldn" */ if (retr >= 3) return 0; else return 1;}static int read_capacity(int host_index, int ldn){ int retr; struct im_scb *scb; struct im_tsb *tsb; unsigned char *buf; scb = &(ld(host_index)[ldn].scb); tsb = &(ld(host_index)[ldn].tsb); buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); ld(host_index)[ldn].tsb.dev_status = 0; for (retr=0; retr<3; retr++) { /*fill scb with read capacity command */ scb->command = IM_READ_CAPACITY_CMD; scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD; last_scsi_type(host_index)[ldn] = IM_SCB; scb->sys_buf_adr = virt_to_bus(buf); scb->sys_buf_length = 8; scb->tsb_adr = virt_to_bus(tsb); /*issue scb to passed ldn, and busy wait for interrupt */ got_interrupt(host_index) = 0; issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); while (!got_interrupt(host_index)) barrier (); /*if got capacity, get block length and return one device found */ if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) return 1; } /*if all three retries failed, return "no device at this ldn" */ if (retr >= 3) return 0; else return 1;}static int get_pos_info(int host_index){ int retr; struct im_scb *scb; struct im_tsb *tsb; unsigned char *buf; scb = &(ld(host_index)[MAX_LOG_DEV].scb); tsb = &(ld(host_index)[MAX_LOG_DEV].tsb); buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf)); ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0; for (retr=0; retr<3; retr++) { /*fill scb with get_pos_info command */ scb->command = IM_GET_POS_INFO_CMD; scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD; last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB; scb->sys_buf_adr = virt_to_bus(buf); if (special(host_index)==IBM_SCSI2_FW) scb->sys_buf_length = 256; /* get all info from F/W adapter */ else scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */ scb->tsb_adr = virt_to_bus(tsb); /*issue scb to ldn=15, and busy wait for interrupt */ got_interrupt(host_index) = 0; issue_cmd (host_index, virt_to_bus(scb), IM_SCB | MAX_LOG_DEV); while (!got_interrupt(host_index)) barrier (); /*if got POS-stuff, get block length and return one device found */ if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) return 1; } /* if all three retries failed, return "no device at this ldn" */ if (retr >= 3) return 0; else return 1;}/* SCSI-immediate-command for assign. This functions maps/unmaps specific ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the subsystem and for dynamical remapping od ldns. */static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation){ int retr; unsigned long imm_cmd; for (retr=0; retr<3; retr++) { /* select mutation level of the SCSI-adapter */ switch (special(host_index)) { case IBM_SCSI2_FW: imm_cmd = (unsigned long)(IM_ASSIGN_IMM_CMD); imm_cmd |= (unsigned long)((lun & 7) << 24); imm_cmd |= (unsigned long)((operation & 1) << 23); imm_cmd |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24); imm_cmd |= (unsigned long)((ldn & 15) << 16); break; default: imm_cmd = inl(IM_CMD_REG(host_index)); imm_cmd &= (unsigned long)(0xF8000000); /* keep reserved bits */ imm_cmd |= (unsigned long)(IM_ASSIGN_IMM_CMD); imm_cmd |= (unsigned long)((lun & 7) << 24); imm_cmd |= (unsigned long)((operation & 1) << 23); imm_cmd |= (unsigned long)((pun & 7) << 20); imm_cmd |= (unsigned long)((ldn & 15) << 16); break; } last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD; last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; got_interrupt(host_index) = 0; issue_cmd (host_index, (unsigned long)(imm_cmd), IM_IMM_CMD | MAX_LOG_DEV); while (!got_interrupt(host_index)) barrier (); /*if command succesful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } if (retr >= 3) return 0; else return 1;}static int immediate_feature(int host_index, unsigned int speed, unsigned int timeout){ int retr; unsigned long imm_cmd; for (retr=0; retr<3; retr++) { /* select mutation level of the SCSI-adapter */ imm_cmd = IM_FEATURE_CTR_IMM_CMD; imm_cmd |= (unsigned long)((speed & 0x7) << 29); imm_cmd |= (unsigned long)((timeout & 0x1fff) << 16); last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD; last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD; got_interrupt(host_index) = 0; /* we need to run into command errors in order to probe for the * right speed! */ global_command_error_excuse = 1; issue_cmd (host_index, (unsigned long)(imm_cmd), IM_IMM_CMD | MAX_LOG_DEV); while (!got_interrupt(host_index)) barrier (); if (global_command_error_excuse == CMD_FAIL) { global_command_error_excuse = 0; return 2; } else global_command_error_excuse = 0; /*if command succesful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } if (retr >= 3) return 0; else return 1;}#ifdef CONFIG_IBMMCA_SCSI_DEV_RESETstatic int immediate_reset(int host_index, unsigned int ldn){ int retries; int ticks; unsigned long imm_command; for (retries=0; retries<3; retries ++) { imm_command = inl(IM_CMD_REG(host_index)); imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */ imm_command |= (unsigned long)(IM_RESET_IMM_CMD); last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD; last_scsi_type(host_index)[ldn] = IM_IMM_CMD; got_interrupt(host_index) = 0; reset_status(host_index) = IM_RESET_IN_PROGRESS; issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn); ticks = IM_RESET_DELAY*HZ; while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) { udelay((1+999/HZ)*1000); barrier(); } /* if reset did not complete, just complain */ if (!ticks) { printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY); reset_status(host_index) = IM_RESET_FINISHED_OK; /* did not work, finish */ return 1; } /*if command succesful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } if (retries >= 3) return 0; else return 1;}#endif/* type-interpreter for physical device numbers */static char *ti_p(int dev){ switch (dev) { case TYPE_IBM_SCSI_ADAPTER: return("A"); case TYPE_DISK: return("D"); case TYPE_TAPE: return("T"); case TYPE_PROCESSOR: return("P"); case TYPE_WORM: return("W"); case TYPE_ROM: return("R"); case TYPE_SCANNER: return("S"); case TYPE_MOD: return("M"); case TYPE_MEDIUM_CHANGER: return("C"); case TYPE_NO_LUN: return("+"); /* show NO_LUN */ } return("-"); /* TYPE_NO_DEVICE and others */}/* interpreter for logical device numbers (ldn) */static char *ti_l(int val){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -