📄 ibmmca.c
字号:
struct logical_device _ld[MAX_LOG_DEV+1]; /* array to convert (pun, lun) into logical device number: */ unsigned char _get_ldn[16][8]; /*array that contains the information about the physical SCSI-devices attached to this host adapter: */ 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(hi) (hosts[(hi)]->this_id)#define subsystem_maxid(hi) (hosts[(hi)]->max_id)#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2])#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3])#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4])#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5])#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->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;#include <linux/module.h>MODULE_PARM(boot_options, "s");MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");MODULE_PARM(display, "1i");MODULE_PARM(adisplay, "1i");MODULE_PARM(normal, "1i");MODULE_PARM(ansi, "1i");#endif/*counter of concurrent disk read/writes, to turn on/off disk led */static int disk_rw_in_progress = 0;/* host information */static int found = 0;static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };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 interrupt_handler (int, void *, struct pt_regs *);static void issue_cmd (int, unsigned long, unsigned char);static void internal_done (Scsi_Cmnd * cmd);static void check_devices (int, int);static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);static int immediate_feature(int, unsigned int, unsigned int);#ifdef CONFIG_IBMMCA_SCSI_DEV_RESETstatic int immediate_reset(int, unsigned int);#endifstatic int device_inquiry(int, int);static int read_capacity(int, int);static int get_pos_info(int);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(int);static int device_exists (int, int, int *, int *);static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, int, int, int, char *);static int option_setup(char *);/* local functions needed for proc_info */static int ldn_access_load(int, int);static int ldn_access_total_read_write(int);static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs){ int host_index, ihost_index; unsigned int intr_reg; unsigned int cmd_result; unsigned int ldn; unsigned long flags; Scsi_Cmnd *cmd; int lastSCSI; IBMLOCK /* search for one adapter-response on shared interrupt */ for (host_index=0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++); /* return if some other device on this IRQ caused the interrupt */ if (!hosts[host_index]) { IBMUNLOCK return; } /* the reset-function already did all the job, even ints got renabled on the subsystem, so just return */ if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)|| (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) { reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS; IBMUNLOCK return; } /*must wait for attention reg not busy, then send EOI to subsystem */ while (1) { if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) break; IBMUNLOCK /* cycle interrupt */ IBMLOCK } ihost_index=host_index; /*get command result and logical device */ intr_reg = (unsigned char)(inb (IM_INTR_REG(ihost_index))); cmd_result = intr_reg & 0xf0; ldn = intr_reg & 0x0f; /* get the last_scsi_command here */ lastSCSI = last_scsi_command(ihost_index)[ldn]; outb (IM_EOI | ldn, IM_ATTN_REG(ihost_index)); IBMUNLOCK /*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("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n"); printk(" Last cmd=0x%x, ena=%x, len=",lastSCSI, ld(ihost_index)[ldn].scb.enable); if (ld(ihost_index)[ldn].cmd) printk("%ld/%ld,",(long)(ld(ihost_index)[ldn].cmd->request_bufflen), (long)(ld(ihost_index)[ldn].scb.sys_buf_length)); else printk("none,"); if (ld(ihost_index)[ldn].cmd) printk("Blocksize=%d",ld(ihost_index)[ldn].scb.u2.blk.length); else printk("Blocksize=none"); printk(", host=0x%x, ldn=0x%x\n",ihost_index, ldn); if (ld(ihost_index)[ldn].cmd) { printk("Blockcount=%d/%d\n",last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count); printk("Logical block=%lx/%lx\n",last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr); } printk("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("IBM MCA SCSI: Subsystem Error-Status follows:\n"); printk(" Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]); printk(" Attention Register..........: %x\n", inb (IM_ATTN_REG(ihost_index))); printk(" Basic Control Register......: %x\n", inb (IM_CTR_REG(ihost_index))); printk(" Interrupt Status Register...: %x\n", intr_reg); printk(" Basic Status Register.......: %x\n", inb (IM_STAT_REG(ihost_index))); if ((last_scsi_type(ihost_index)[ldn]==IM_SCB)|| (last_scsi_type(ihost_index)[ldn]==IM_LONG_SCB)) { printk(" SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command); printk(" SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable); printk(" SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr); printk(" SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr); printk(" SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length); printk(" SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr); printk(" SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr); printk(" SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count); printk(" SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length); } printk(" Send this report to the maintainer.\n"); panic("IBM MCA SCSI: Fatal errormessage 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(ihost_index).total_interrupts++; /*only for local checking phase */ if (local_checking_phase_flag(ihost_index)) { stat_result(ihost_index) = cmd_result; got_interrupt(ihost_index) = 1; reset_status(ihost_index) = IM_RESET_FINISHED_OK; last_scsi_command(ihost_index)[ldn] = NO_SCSI; return; } /* handling of commands coming from upper level of scsi driver */ if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) { /* verify ldn, and may handle rare reset immediate command */ if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS)&& (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) { if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { disk_rw_in_progress = 0; PS2_DISK_LED_OFF (); reset_status(ihost_index) = IM_RESET_FINISHED_FAIL; } else { /*reset disk led counter, turn off disk led */ disk_rw_in_progress = 0; PS2_DISK_LED_OFF (); reset_status(ihost_index) = IM_RESET_FINISHED_OK; } stat_result(ihost_index) = cmd_result; last_scsi_command(ihost_index)[ldn] = NO_SCSI; last_scsi_type(ihost_index)[ldn] = 0; return; } else if (last_scsi_command(ihost_index)[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(ihost_index)[ldn].cmd; ld(ihost_index)[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(ihost_index) = cmd_result; last_scsi_command(ihost_index)[ldn] = NO_SCSI; last_scsi_type(ihost_index)[ldn] = 0; if (cmd->scsi_done) (cmd->scsi_done)(cmd); /* should be the internal_done */ return; } else { disk_rw_in_progress = 0; PS2_DISK_LED_OFF (); reset_status(ihost_index) = IM_RESET_FINISHED_OK; stat_result(ihost_index) = cmd_result; last_scsi_command(ihost_index)[ldn] = NO_SCSI;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -