ibmmca.c
来自「linux 内核源代码」· C语言 代码 · 共 1,772 行 · 第 1/5 页
C
1,772 行
unsigned char _get_scsi[16][8]; /* used only when checking logical devices: */ int _local_checking_phase_flag; /* report received interrupt: */ int _got_interrupt; /* report termination-status of SCSI-command: */ int _stat_result; /* reset status (used only when doing reset): */ int _reset_status; /* code of the last SCSI command (needed for panic info): */ int _last_scsi_command[MAX_LOG_DEV + 1]; /* identifier of the last SCSI-command type */ int _last_scsi_type[MAX_LOG_DEV + 1]; /* last blockcount */ int _last_scsi_blockcount[MAX_LOG_DEV + 1]; /* last locgical block address */ unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1]; /* Counter that points on the next reassignable ldn for dynamical remapping. The default value is 7, that is the first reassignable number in the list at boottime: */ int _next_ldn; /* Statistics-structure for this IBM-SCSI-host: */ struct Driver_Statistics _IBM_DS; /* This hostadapters pos-registers pos2 until pos6 */ unsigned int _pos[8]; /* assign a special variable, that contains dedicated info about the adaptertype */ int _special; /* connector size on the MCA bus */ int _connector_size; /* synchronous SCSI transfer rate bitpattern */ int _adapter_speed;};/* macros to access host data structure */#define subsystem_pun(h) ((h)->this_id)#define subsystem_maxid(h) ((h)->max_id)#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld)#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn)#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi)#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag)#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt)#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result)#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status)#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command)#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount)#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block)#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn)#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS)#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special)#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size)#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed)#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2])#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3])#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4])#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5])#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6])/* Define a arbitrary number as subsystem-marker-type. This number is, as described in the ANSI-SCSI-standard, not occupied by other device-types. */#define TYPE_IBM_SCSI_ADAPTER 0x2F/* Define 0xFF for no device type, because this type is not defined within the ANSI-SCSI-standard, therefore, it can be used and should not cause any harm. */#define TYPE_NO_DEVICE 0xFF/* define medium-changer. If this is not defined previously, e.g. Linux 2.0.x, define this type here. */#ifndef TYPE_MEDIUM_CHANGER#define TYPE_MEDIUM_CHANGER 0x08#endif/* define possible operations for the immediate_assign command */#define SET_LDN 0#define REMOVE_LDN 1/* ldn which is used to probe the SCSI devices */#define PROBE_LDN 0/* reset status flag contents */#define IM_RESET_NOT_IN_PROGRESS 0#define IM_RESET_IN_PROGRESS 1#define IM_RESET_FINISHED_OK 2#define IM_RESET_FINISHED_FAIL 3#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4#define IM_RESET_FINISHED_OK_NO_INT 5/* define undefined SCSI-command */#define NO_SCSI 0xffff/*-----------------------------------------------------------------------*//* if this is nonzero, ibmmcascsi option has been passed to the kernel */static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };/* fill module-parameters only, when this define is present. (that is kernel version 2.1.x) */#if defined(MODULE)static char *boot_options = NULL;module_param(boot_options, charp, 0);module_param_array(io_port, int, NULL, 0);module_param_array(scsi_id, int, NULL, 0);MODULE_LICENSE("GPL");#endif/*counter of concurrent disk read/writes, to turn on/off disk led */static int disk_rw_in_progress = 0;static unsigned int pos[8]; /* whole pos register-line for diagnosis *//* Taking into account the additions, made by ZP Gu. * This selects now the preset value from the configfile and * offers the 'normal' commandline option to be accepted */#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARDstatic char ibm_ansi_order = 1;#elsestatic char ibm_ansi_order = 0;#endifstatic void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char);static void internal_done(Scsi_Cmnd * cmd);static void check_devices(struct Scsi_Host *, int);static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int);static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int);#ifdef CONFIG_IBMMCA_SCSI_DEV_RESETstatic int immediate_reset(struct Scsi_Host *, unsigned int);#endifstatic int device_inquiry(struct Scsi_Host *, int);static int read_capacity(struct Scsi_Host *, int);static int get_pos_info(struct Scsi_Host *);static char *ti_p(int);static char *ti_l(int);static char *ibmrate(unsigned int, int);static int probe_display(int);static int probe_bus_mode(struct Scsi_Host *);static int device_exists(struct Scsi_Host *, int, int *, int *);static int option_setup(char *);/* local functions needed for proc_info */static int ldn_access_load(struct Scsi_Host *, int);static int ldn_access_total_read_write(struct Scsi_Host *);static irqreturn_t interrupt_handler(int irq, void *dev_id){ unsigned int intr_reg; unsigned int cmd_result; unsigned int ldn; unsigned long flags; Scsi_Cmnd *cmd; int lastSCSI; struct device *dev = dev_id; struct Scsi_Host *shpnt = dev_get_drvdata(dev); spin_lock_irqsave(shpnt->host_lock, flags); if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) { spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_NONE; } /* the reset-function already did all the job, even ints got renabled on the subsystem, so just return */ if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) { reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS; spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; } /*must wait for attention reg not busy, then send EOI to subsystem */ while (1) { if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY)) break; cpu_relax(); } /*get command result and logical device */ intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt))); cmd_result = intr_reg & 0xf0; ldn = intr_reg & 0x0f; /* get the last_scsi_command here */ lastSCSI = last_scsi_command(shpnt)[ldn]; outb(IM_EOI | ldn, IM_ATTN_REG(shpnt)); /*these should never happen (hw fails, or a local programming bug) */ if (!global_command_error_excuse) { switch (cmd_result) { /* Prevent from Ooopsing on error to show the real reason */ case IM_ADAPTER_HW_FAILURE: case IM_SOFTWARE_SEQUENCING_ERROR: case IM_CMD_ERROR: printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n"); printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable); if (ld(shpnt)[ldn].cmd) printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length)); else printk("none,"); if (ld(shpnt)[ldn].cmd) printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length); else printk("Blocksize=none"); printk(", host=%p, ldn=0x%x\n", shpnt, ldn); if (ld(shpnt)[ldn].cmd) { printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count); printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr); } printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN"); /* if errors appear, enter this section to give detailed info */ printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n"); printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(shpnt)[ldn]); printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt))); printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt))); printk(KERN_ERR " Interrupt Status Register...: %x\n", intr_reg); printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt))); if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) { printk(KERN_ERR " SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command); printk(KERN_ERR " SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable); printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr); printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr); printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length); printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr); printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr); printk(KERN_ERR " SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count); printk(KERN_ERR " SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length); } printk(KERN_ERR " Send this report to the maintainer.\n"); panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result); break; } } else { /* The command error handling is made silent, but we tell the * calling function, that there is a reported error from the * adapter. */ switch (cmd_result) { case IM_ADAPTER_HW_FAILURE: case IM_SOFTWARE_SEQUENCING_ERROR: case IM_CMD_ERROR: global_command_error_excuse = CMD_FAIL; break; default: global_command_error_excuse = 0; break; } } /* if no panic appeared, increase the interrupt-counter */ IBM_DS(shpnt).total_interrupts++; /*only for local checking phase */ if (local_checking_phase_flag(shpnt)) { stat_result(shpnt) = cmd_result; got_interrupt(shpnt) = 1; reset_status(shpnt) = IM_RESET_FINISHED_OK; last_scsi_command(shpnt)[ldn] = NO_SCSI; spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; } /* handling of commands coming from upper level of scsi driver */ if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) { /* verify ldn, and may handle rare reset immediate command */ if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) { if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { disk_rw_in_progress = 0; PS2_DISK_LED_OFF(); reset_status(shpnt) = IM_RESET_FINISHED_FAIL; } else { /*reset disk led counter, turn off disk led */ disk_rw_in_progress = 0; PS2_DISK_LED_OFF(); reset_status(shpnt) = IM_RESET_FINISHED_OK; } stat_result(shpnt) = cmd_result; last_scsi_command(shpnt)[ldn] = NO_SCSI; last_scsi_type(shpnt)[ldn] = 0; spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; } else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) { /* react on SCSI abort command */#ifdef IM_DEBUG_PROBE printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");#endif disk_rw_in_progress = 0; PS2_DISK_LED_OFF(); cmd = ld(shpnt)[ldn].cmd; ld(shpnt)[ldn].cmd = NULL; if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) cmd->result = DID_NO_CONNECT << 16; else cmd->result = DID_ABORT << 16; stat_result(shpnt) = cmd_result; last_scsi_command(shpnt)[ldn] = NO_SCSI; last_scsi_type(shpnt)[ldn] = 0; if (cmd->scsi_done) (cmd->scsi_done) (cmd); /* should be the internal_done */ spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; } else { disk_rw_in_progress = 0; PS2_DISK_LED_OFF(); reset_status(shpnt) = IM_RESET_FINISHED_OK; stat_result(shpnt) = cmd_result; last_scsi_command(shpnt)[ldn] = NO_SCSI; spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; } } last_scsi_command(shpnt)[ldn] = NO_SCSI; last_scsi_type(shpnt)[ldn] = 0; cmd = ld(shpnt)[ldn].cmd; ld(shpnt)[ldn].cmd = NULL;#ifdef IM_DEBUG_TIMEOUT if (cmd) { if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) { spin_unlock_irqsave(shpnt->host_lock, flags); printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun); return IRQ_HANDLED; } }#endif /*if no command structure, just return, else clear cmd */ if (!cmd) { spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED; }#ifdef IM_DEBUG_INT printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error);#endif /*if this is end of media read/write, may turn off PS/2 disk led */ if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[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(shpnt)[ldn].tsb.dev_status & 0x1e); IBM_DS(shpnt).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); spin_unlock_irqrestore(shpnt->host_lock, flags); return IRQ_HANDLED;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?