📄 ultrastor.c
字号:
aborted: set_bit(mscp_index, &config.mscp_free); /* If the driver queues commands, call the done proc here. Otherwise return an error. */#if ULTRASTOR_MAX_CMDS > 1 SCpnt->result = status; done(SCpnt); return 0;#else return status;#endif } /* Store pointer in OGM address bytes */ outl((unsigned int)my_mscp, config.ogm_address); /* Issue OGM interrupt */ if (config.slot) { /* Write OGM command register on 24F */ outb(1, config.ogm_address - 1); outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address)); } else { outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address)); } restore_flags(flags);#if (ULTRASTOR_DEBUG & UD_COMMAND) printk("USx4F: queuecommand: returning\n");#endif return 0;}/* This code must deal with 2 cases: 1. The command has not been written to the OGM. In this case, set the abort flag and return. 2. The command has been written to the OGM and is stuck somewhere in the adapter. 2a. On a 24F, ask the adapter to abort the command. It will interrupt when it does. 2b. Call the command's done procedure. */int ultrastor_abort(Scsi_Cmnd *SCpnt){#if ULTRASTOR_DEBUG & UD_ABORT char out[108]; unsigned char icm_status = 0, ogm_status = 0; unsigned int icm_addr = 0, ogm_addr = 0;#endif unsigned int mscp_index; unsigned char old_aborted; void (*done)(Scsi_Cmnd *); if(config.slot) return SCSI_ABORT_SNOOZE; /* Do not attempt an abort for the 24f */ /* Simple consistency checking */ if(!SCpnt->host_scribble) return SCSI_ABORT_NOT_RUNNING; mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp; if (mscp_index >= ULTRASTOR_MAX_CMDS) panic("Ux4F aborting invalid MSCP");#if ULTRASTOR_DEBUG & UD_ABORT if (config.slot) { int port0 = (config.slot << 12) | 0xc80; int i; int flags; save_flags(flags); cli(); strcpy(out, "OGM %d:%x ICM %d:%x ports: "); for (i = 0; i < 16; i++) { unsigned char p = inb(port0 + i); out[28 + i * 3] = "0123456789abcdef"[p >> 4]; out[29 + i * 3] = "0123456789abcdef"[p & 15]; out[30 + i * 3] = ' '; } out[28 + i * 3] = '\n'; out[29 + i * 3] = 0; ogm_status = inb(port0 + 22); ogm_addr = inl(port0 + 23); icm_status = inb(port0 + 27); icm_addr = inl(port0 + 28); restore_flags(flags); } /* First check to see if an interrupt is pending. I suspect the SiS chipset loses interrupts. (I also suspect is mangles data, but one bug at a time... */ if (config.slot ? inb(config.icm_address - 1) == 2 : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) { int flags; save_flags(flags); printk("Ux4F: abort while completed command pending\n"); restore_flags(flags); cli(); ultrastor_interrupt(0, NULL, NULL); restore_flags(flags); return SCSI_ABORT_SUCCESS; /* FIXME - is this correct? -ERY */ }#endif old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]); /* aborted == 0xff is the signal that queuecommand has not yet sent the command. It will notice the new abort flag and fail. */ if (old_aborted == 0xff) return SCSI_ABORT_SUCCESS; /* On 24F, send an abort MSCP request. The adapter will interrupt and the interrupt handler will call done. */ if (config.slot && inb(config.ogm_address - 1) == 0) { int flags; save_flags(flags); cli(); outl((int)&config.mscp[mscp_index], config.ogm_address); inb(0xc80); /* delay */ outb(0x80, config.ogm_address - 1); outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));#if ULTRASTOR_DEBUG & UD_ABORT log_ultrastor_abort(&config, mscp_index); printk(out, ogm_status, ogm_addr, icm_status, icm_addr);#endif restore_flags(flags); return SCSI_ABORT_PENDING; }#if ULTRASTOR_DEBUG & UD_ABORT log_ultrastor_abort(&config, mscp_index);#endif /* Can't request a graceful abort. Either this is not a 24F or the OGM is busy. Don't free the command -- the adapter might still be using it. Setting SCint = 0 causes the interrupt handler to ignore the command. */ /* FIXME - devices that implement soft resets will still be running the command after a bus reset. We would probably rather leave the command in the queue. The upper level code will automatically leave the command in the active state instead of requeueing it. ERY */#if ULTRASTOR_DEBUG & UD_ABORT if (config.mscp[mscp_index].SCint != SCpnt) printk("abort: command mismatch, %p != %p\n", config.mscp[mscp_index].SCint, SCpnt);#endif if (config.mscp[mscp_index].SCint == 0) return SCSI_ABORT_NOT_RUNNING; if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); config.mscp[mscp_index].SCint = 0; done = config.mscp[mscp_index].done; config.mscp[mscp_index].done = 0; SCpnt->result = DID_ABORT << 16; /* I worry about reentrancy in scsi.c */ done(SCpnt); /* Need to set a timeout here in case command never completes. */ return SCSI_ABORT_SUCCESS;}int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags){ int flags; register int i;#if (ULTRASTOR_DEBUG & UD_RESET) printk("US14F: reset: called\n");#endif if(config.slot) return SCSI_RESET_PUNT; /* Do not attempt a reset for the 24f */ save_flags(flags); cli(); /* Reset the adapter and SCSI bus. The SCSI bus reset can be inhibited by clearing ultrastor_bus_reset before probe. */ outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address)); if (config.slot) { outb(0, config.ogm_address - 1); outb(0, config.icm_address - 1); }#if ULTRASTOR_MAX_CMDS == 1 if (config.mscp_busy && config.mscp->done && config.mscp->SCint) { config.mscp->SCint->result = DID_RESET << 16; config.mscp->done(config.mscp->SCint); } config.mscp->SCint = 0;#else for (i = 0; i < ULTRASTOR_MAX_CMDS; i++) { if (! (config.mscp_free & (1 << i)) && config.mscp[i].done && config.mscp[i].SCint) { config.mscp[i].SCint->result = DID_RESET << 16; config.mscp[i].done(config.mscp[i].SCint); config.mscp[i].done = 0; } config.mscp[i].SCint = 0; }#endif /* FIXME - if the device implements soft resets, then the command will still be running. ERY */ memset((unsigned char *)config.aborted, 0, sizeof config.aborted);#if ULTRASTOR_MAX_CMDS == 1 config.mscp_busy = 0;#else config.mscp_free = ~0;#endif restore_flags(flags); return SCSI_RESET_SUCCESS;}int ultrastor_biosparam(Disk * disk, kdev_t dev, int * dkinfo){ int size = disk->capacity; unsigned int s = config.heads * config.sectors; dkinfo[0] = config.heads; dkinfo[1] = config.sectors; dkinfo[2] = size / s; /* Ignore partial cylinders */#if 0 if (dkinfo[2] > 1024) dkinfo[2] = 1024;#endif return 0;}static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs){ unsigned int status;#if ULTRASTOR_MAX_CMDS > 1 unsigned int mscp_index;#endif register struct mscp *mscp; void (*done)(Scsi_Cmnd *); Scsi_Cmnd *SCtmp;#if ULTRASTOR_MAX_CMDS == 1 mscp = &config.mscp[0];#else mscp = (struct mscp *)inl(config.icm_address); mscp_index = mscp - config.mscp; if (mscp_index >= ULTRASTOR_MAX_CMDS) { printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp); /* A command has been lost. Reset and report an error for all commands. */ ultrastor_reset(NULL, 0); return; }#endif /* Clean ICM slot (set ICMINT bit to 0) */ if (config.slot) { unsigned char icm_status = inb(config.icm_address - 1);#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT) if (icm_status != 1 && icm_status != 2) printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status, mscp_index, (unsigned int) mscp);#endif /* The manual says clear interrupt then write 0 to ICM status. This seems backwards, but I'll do it anyway. --jfc */ outb(2, SYS_DOORBELL_INTR(config.doorbell_address)); outb(0, config.icm_address - 1); if (icm_status == 4) { printk("UltraStor abort command failed\n"); return; } if (icm_status == 3) { void (*done)(Scsi_Cmnd *) = mscp->done; if (done) { mscp->done = 0; mscp->SCint->result = DID_ABORT << 16; done(mscp->SCint); } return; } } else { outb(1, SYS_DOORBELL_INTR(config.doorbell_address)); } SCtmp = mscp->SCint; mscp->SCint = NULL; if (SCtmp == 0) {#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);#endif #if ULTRASTOR_MAX_CMDS == 1 config.mscp_busy = FALSE;#else set_bit(mscp_index, &config.mscp_free);#endif config.aborted[mscp_index] = 0; return; } /* Save done locally and zero before calling. This is needed as once we call done, we may get another command queued before this interrupt service routine can return. */ done = mscp->done; mscp->done = 0; /* Let the higher levels know that we're done */ switch (mscp->adapter_status) { case 0: status = DID_OK << 16; break; case 0x01: /* invalid command */ case 0x02: /* invalid parameters */ case 0x03: /* invalid data list */ default: status = DID_ERROR << 16; break; case 0x84: /* SCSI bus abort */ status = DID_ABORT << 16; break; case 0x91: status = DID_TIME_OUT << 16; break; } SCtmp->result = status | mscp->target_status; SCtmp->host_scribble = 0; /* Free up mscp block for next command */#if ULTRASTOR_MAX_CMDS == 1 config.mscp_busy = FALSE;#else set_bit(mscp_index, &config.mscp_free);#endif#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) if (config.aborted[mscp_index]) printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n", mscp_index, (unsigned int) mscp, config.aborted[mscp_index]);#endif config.aborted[mscp_index] = 0; if (done) done(SCtmp); else printk("US14F: interrupt: unexpected interrupt\n"); if (config.slot ? inb(config.icm_address - 1) : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))#if (ULTRASTOR_DEBUG & UD_MULTI_CMD) printk("Ux4F: multiple commands completed\n");#else ;#endif#if (ULTRASTOR_DEBUG & UD_INTERRUPT) printk("USx4F: interrupt: returning\n");#endif}#ifdef MODULE/* Eventually this will go into an include file, but this will be later */Scsi_Host_Template driver_template = ULTRASTOR_14F;#include "scsi_module.c"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -