📄 sim710.c
字号:
case READ_TOC: datain = 1; dataout = 0; break; case MODE_SELECT: case WRITE_6: case WRITE_10: datain = 0; dataout = 1; break; case TEST_UNIT_READY: case ALLOW_MEDIUM_REMOVAL: case START_STOP: datain = dataout = 0; break; default: datain = dataout = 1; } memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND); targdata->dsa_msgout[0] = IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0); if (hostdata->negotiate & (1 << cmd->target)) { if (opt_noneg & (1 << cmd->target)) { hostdata->negotiate ^= (1 << cmd->target); targdata->dsa[DSA_MSGOUT] = 1; } else { DEB(DEB_SYNC, printk("scsi%d: Negotiating async transfers " "for ID %d\n", host->host_no, cmd->target)); memcpy(targdata->dsa_msgout+1, async_message, sizeof(async_message)); targdata->dsa[DSA_MSGOUT] = sizeof(async_message) + 1; } } else targdata->dsa[DSA_MSGOUT] = 1; targdata->dsa_msgin[0] = 0xff; targdata->dsa_status[0] = 0xff; targdata->dsa[DSA_SELECT] = (1 << cmd->target) << 16; targdata->dsa[DSA_MSGOUT+1] = virt_to_bus(targdata->dsa_msgout); targdata->dsa[DSA_CMND] = cmd->cmd_len; targdata->dsa[DSA_CMND+1] = virt_to_bus(targdata->dsa_cdb); targdata->dsa[DSA_STATUS] = 1; targdata->dsa[DSA_STATUS+1] = virt_to_bus(targdata->dsa_status); targdata->dsa[DSA_MSGIN] = 1; targdata->dsa[DSA_MSGIN+1] = virt_to_bus(targdata->dsa_msgin); sg_start = (MAX_SG - (cmd->use_sg ? cmd->use_sg : 1)) * 2; dip = targdata->dsa + DSA_DATAIN + sg_start; dop = targdata->dsa + DSA_DATAOUT + sg_start; for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; i++) { u32 vbuf = cmd->use_sg ? (u32)(((struct scatterlist *)cmd->buffer)[i].address) : (u32)(cmd->request_buffer); u32 bbuf = virt_to_bus((void *)vbuf); u32 cnt = cmd->use_sg ? ((struct scatterlist *)cmd->buffer)[i].length : cmd->request_bufflen; if (datain) {#ifdef CONFIG_TP34V_SCSI cache_clear(virt_to_phys((void *)vbuf), cnt);#endif *dip++ = cnt; *dip++ = bbuf; } if (dataout) {#ifdef CONFIG_TP34V_SCSI cache_push(virt_to_phys((void *)vbuf), cnt);#endif *dop++ = cnt; *dop++ = bbuf; } } targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] = virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_start + 2); targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] = virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_start + 2); for (i = 0, dsa = virt_to_bus(targdata->dsa); i < 4; i++) { u32 v = hostdata->script[Ent_patch_new_dsa/4 + i * 2]; v &= ~0x0000ff00; v |= (dsa & 0xff) << 8; hostdata->script[Ent_patch_new_dsa/4 + i * 2] = v; dsa >>= 8; } hostdata->running = targdata->cur_cmd = cmd; hostdata->state = STATE_BUSY; NCR_write8(ISTAT_REG, ISTAT_10_SIGP);}static volatile int process_issue_queue_running = 0; static __inline__ void run_process_issue_queue(struct sim710_hostdata *hostdata){ unsigned long flags; save_flags (flags); cli(); if (!process_issue_queue_running) { process_issue_queue_running = 1; process_issue_queue(hostdata, flags); /* * process_issue_queue_running is cleared in process_issue_queue * once it can't do more work, and process_issue_queue exits with * interrupts disabled. */ } restore_flags (flags);}/* * Function : process_issue_queue (hostdata, flags) * * Purpose : Start next command for any idle target. * * NOTE : process_issue_queue exits with interrupts *disabled*, so the * caller must reenable them if it desires. * * NOTE : process_issue_queue should be called from both * sim710_queue_command() and from the interrupt handler * after command completion. */static void process_issue_queue (struct sim710_hostdata *hostdata, unsigned long flags){ Scsi_Cmnd *tmp, *prev; int done; /* * We run (with interrupts disabled) until we're sure that none of * the host adapters have anything that can be done, at which point * we set process_issue_queue_running to 0 and exit. * * Interrupts are enabled before doing various other internal * instructions, after we've decided that we need to run through * the loop again. * */ do { cli(); /* Freeze request queues */ done = 1; if (hostdata->issue_queue) { if (hostdata->state == STATE_DISABLED) { tmp = (Scsi_Cmnd *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr; tmp->result = (DID_BAD_TARGET << 16); tmp->scsi_done (tmp); done = 0; } else if (hostdata->state == STATE_IDLE) { for (tmp = hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->SCp.ptr) { if (hostdata->target[tmp->target].cur_cmd == NULL) { if (prev) prev->SCp.ptr = tmp->SCp.ptr; else hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr; tmp->SCp.ptr = NULL; run_command (hostdata, tmp); done = 0; } /* if target/lun is not busy */ } /* scan issue queue for work */ } /* host is idle */ } /* if hostdata->issue_queue */ if (!done) restore_flags (flags); } while (!done); process_issue_queue_running = 0;}intsim710_queuecommand(Scsi_Cmnd * cmd, void (*done)(Scsi_Cmnd *)){ struct Scsi_Host *host = cmd->host; struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0]; Scsi_Cmnd *tmp; unsigned long flags; if (cmd->lun) { /* Silently ignore luns other than zero! */ cmd->result = (DID_BAD_TARGET << 16); done(cmd); return 0; } DEB(DEB_CMND, printk("scsi%d: id%d queuing ", host->host_no, cmd->target)); DEB(DEB_CMND, print_command(cmd->cmnd)); cmd->scsi_done = done; cmd->host_scribble = NULL; cmd->SCp.ptr = NULL; cmd->SCp.buffer = NULL; save_flags(flags); cli(); if (ignore_ids & (1 << cmd->target)) { printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target); cmd->result = (DID_BAD_TARGET << 16); done(cmd); restore_flags (flags); return 0; }#ifdef DEBUG_LIMIT_INTS if (sim710_intrs > DEBUG_LIMIT_INTS) { cmd->result = (DID_BAD_TARGET << 16); done(cmd); restore_flags (flags); return 0; }#endif if (cmd->use_sg > MAX_SG) panic ("cmd->use_sg = %d\n", cmd->use_sg); if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { for (tmp = hostdata->issue_queue; tmp->SCp.ptr; tmp = (Scsi_Cmnd *) tmp->SCp.ptr); tmp->SCp.ptr = (unsigned char *) cmd; } restore_flags (flags); run_process_issue_queue(hostdata); return 0;}intsim710_detect(Scsi_Host_Template * tpnt){ unsigned char irq_vector; unsigned char scsi_id; unsigned int base_addr; struct Scsi_Host * host = NULL; struct sim710_hostdata *hostdata; int chips = 0; int indx; int revision; int order, size;#ifdef MODULE if (sim710) param_setup(sim710);#endif if (no_of_boards < 0) { printk("sim710: NCR53C710 driver disabled\n"); return 0; }#ifdef CONFIG_MCA /* If board details have been specified via boot/module parameters, * then don't bother probing. */ if (no_of_boards == 0) { int slot; int pos[3]; int mca_53c710_ids[] = MCA_53C710_IDS; int *id_to_check = mca_53c710_ids; static int io_004f_by_pos[] = MCA_004F_IO_PORTS; static int irq_004f_by_pos[] = MCA_004F_IRQS; static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS; static int irq_01bb_by_pos[] = MCA_01BB_IRQS; while ( *id_to_check && no_of_boards < MAXBOARDS) { if (!MCA_bus) return 0; if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) { pos[0] = mca_read_stored_pos(slot, 2); pos[1] = mca_read_stored_pos(slot, 3); pos[2] = mca_read_stored_pos(slot, 4); /* * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2] * * 000000 <disabled> 001010 0x2800 * 000001 <invalid> 001011 0x2C00 * 000010 0x0800 001100 0x3000 * 000011 0x0C00 001101 0x3400 * 000100 0x1000 001110 0x3800 * 000101 0x1400 001111 0x3C00 * 000110 0x1800 010000 0x4000 * 000111 0x1C00 010001 0x4400 * 001000 0x2000 010010 0x4800 * 001001 0x2400 010011 0x4C00 * 010100 0x5000 * * 00F4 port base by bits 3,2,1 in pos[0] * * 000 <disabled> 001 0x200 * 010 0x300 011 0x400 * 100 0x500 101 0x600 * * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6: * * 00 3 10 11 * 01 5 11 14 * * 00F4 IRQ specified by bits 6,5,4 in pos[0] * * 100 5 101 9 * 110 14 */ if ( *id_to_check == 0x01bb || *id_to_check == 0x01ba ) { bases[no_of_boards] = io_01bb_by_pos[(pos[2] & 0xFC) >> 2]; irq_vectors[no_of_boards] = irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)]; if (bases[no_of_boards] == 0x0000) printk("sim710: NCR53C710 Adapter ID 0x01bb is disabled.\n"); else { no_of_boards++; if ( *id_to_check == 0x01bb ) mca_set_adapter_name( slot, "NCR 3360/3430 SCSI SubSystem" ); else mca_set_adapter_name(slot, "NCR Dual SIOP SCSI Host Adapter Board"); } } else if ( *id_to_check == 0x004f ) { bases[no_of_boards] = io_004f_by_pos[((pos[0] & 0x0E) >> 1)]; irq_vectors[no_of_boards] = irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4]; if (bases[no_of_boards] == 0x0000) printk("sim710: NCR53C710 Adapter ID 0x004f is disabled.\n"); else { no_of_boards++; mca_set_adapter_name(slot, "NCR 53c710 SCSI Host Adapter Board"); } } } id_to_check++; } }#endif if (!no_of_boards) { printk("sim710: No NCR53C710 adapter found.\n"); return 0; } size = sizeof(struct sim710_hostdata); order = 0; while (size > (PAGE_SIZE << order)) order++; size = PAGE_SIZE << order; DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n", sizeof(struct sim710_hostdata), size, order)); tpnt->proc_name = "sim710"; for(indx = 0; indx < no_of_boards; indx++) { unsigned long page = __get_free_pages(GFP_ATOMIC, order); if(page == 0UL) { printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx); break; } host = scsi_register(tpnt, 4); if(host == NULL) break; host->hostdata[0] = page; hostdata = (struct sim710_hostdata *)host->hostdata[0]; memset(hostdata, 0, size);#ifdef CONFIG_TP34V_SCSI cache_push(virt_to_phys(hostdata), size); cache_clear(virt_to_phys(hostdata), size); kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);#endif scsi_id = 7; base_addr = bases[indx]; irq_vector = irq_vectors[indx]; printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n", scsi_id, base_addr, irq_vector); DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n", hostdata, sizeof(struct sim710_hostdata), hostdata->target[0].dsa)); hostdata->chip = indx; host->irq = irq_vector; host->this_id = scsi_id; host->unique_id = base_addr; host->base = base_addr; ncr_halt(host); revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4; printk("scsi%d: Revision 0x%x\n",host->host_no,revision); sim710_soft_reset(host); sim710_driver_init(host);#ifdef CONFIG_TP34V_SCSI if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))#else if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))#endif { printk("scsi%d : IRQ%d not free, detaching\n", host->host_no, host->irq); scsi_unregister (host); } else {#ifdef IO_MAPPED request_region((u32)host->base, 64, "sim710");#endif chips++; } NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4)); hostdata->state = STATE_IDLE; } return chips;}intsim710_abort(Scsi_Cmnd * cmd){ struct Scsi_Host * host = cmd->host; printk("scsi%d: Unable to abort command for target %d\n", host->host_no, cmd->target); return FAILED;}/* * This is a device reset. Need to select and send a Bus Device Reset msg. */intsim710_dev_reset(Scsi_Cmnd * SCpnt){ struct Scsi_Host * host = SCpnt->host; printk("scsi%d: Unable to send Bus Device Reset for target %d\n", host->host_no, SCpnt->target); return FAILED;}/* * This is bus reset. We need to reset the bus and fail any active commands. */intsim710_bus_reset(Scsi_Cmnd * SCpnt){ struct Scsi_Host * host = SCpnt->host; printk("scsi%d: Unable to do SCSI bus reset\n", host->host_no); return FAILED;}static intfull_reset(struct Scsi_Host * host){ struct sim710_hostdata *hostdata = (struct sim710_hostdata *) host->hostdata[0]; int target; Scsi_Cmnd *cmd; ncr_halt(host); printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n", host->host_no, NCR_read32(DSP_REG), ((u32)bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4, NCR_read32(SCRATCH_REG)); for (target = 0; target < 7; target++) { if ((cmd = hostdata->target[target].cur_cmd)) { printk("scsi%d: Failing command for ID%d\n", host->host_no, target); cmd->result = DID_RESET << 16; cmd->scsi_done(cmd); hostdata->target[target].cur_cmd = NULL; } } sim710_soft_reset(host); sim710_driver_init(host); NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4)); hostdata->state = STATE_IDLE; run_process_issue_queue(hostdata); return SUCCESS;}/* * This is host reset. We need to reset the chip and the bus. */intsim710_host_reset(Scsi_Cmnd * SCpnt){ struct Scsi_Host * host = SCpnt->host; printk("scsi%d: >>>>>>>>>>>> Host reset <<<<<<<<<<<<\n", host->host_no); return full_reset(host);}#ifdef MODULEintsim710_release(struct Scsi_Host *host){ free_irq(host->irq, host);#ifdef IO_MAPPED release_region((u32)host->base, 64);#endif return 1;}#endifstatic Scsi_Host_Template driver_template = SIM710_SCSI;#include "scsi_module.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -