📄 am53c974.c
字号:
** Purpose : initializes instance and corresponding AM53/79C974 chip,** Inputs : tpnt - template, pci_config - PCI configuration,* * Returns : 1 on success, 0 on failure.* * NOTE: If no override for the controller's SCSI id is given and AM53C974_SCSI_ID * is not defined we assume that the SCSI address of this controller is correctly* set up by the BIOS (as reflected by contents of register CNTLREG1).* This is the only BIOS assistance we need.**************************************************************************/__initfunc(static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev)){ AM53C974_local_declare(); int i, j; struct Scsi_Host *instance, *search; struct AM53C974_hostdata *hostdata;#ifdef AM53C974_OPTION_DEBUG_PROBE_ONLY printk("AM53C974: probe only enabled, aborting initialization\n"); return 0;#endif instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata)); hostdata = (struct AM53C974_hostdata *) instance->hostdata; instance->base = NULL; instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; instance->irq = pdev->irq; instance->dma_channel = -1; AM53C974_setio(instance);#ifdef AM53C974_SCSI_ID instance->this_id = AM53C974_SCSI_ID; AM53C974_write_8(CNTLREG1, instance->this_id & CNTLREG1_SID);#else instance->this_id = AM53C974_read_8(CNTLREG1) & CNTLREG1_SID; if (instance->this_id != 7) printk("scsi%d: WARNING: unusual hostadapter SCSI id %d; please verify!\n", instance->host_no, instance->this_id);#endif for (i = 0; i < sizeof(hostdata->msgout); i++) { hostdata->msgout[i] = NOP; hostdata->last_message[i] = NOP; } for (i = 0; i < 8; i++) { hostdata->busy[i] = 0; hostdata->sync_per[i] = DEF_STP; hostdata->sync_off[i] = 0; hostdata->sync_neg[i] = 0; hostdata->sync_en[i] = DEFAULT_SYNC_NEGOTIATION_ENABLED; hostdata->max_rate[i] = DEFAULT_RATE; hostdata->max_offset[i] = DEFAULT_SYNC_OFFSET; }/* overwrite defaults by LILO overrides */ for (i = 0; i < commandline_current; i++) { if (overrides[i].host_scsi_id == instance->this_id) { j = overrides[i].target_scsi_id; hostdata->sync_en[j] = 1; hostdata->max_rate[j] = overrides[i].max_rate; hostdata->max_offset[j] = overrides[i].max_offset; } } hostdata->sel_cmd = NULL; hostdata->connected = NULL; hostdata->issue_queue = NULL; hostdata->disconnected_queue = NULL; hostdata->in_reset = 0; hostdata->aborted = 0; hostdata->selecting = 0; hostdata->disconnecting = 0; hostdata->dma_busy = 0;/* Set up an interrupt handler if we aren't already sharing an IRQ with another board */ for (search = first_host; search && (((the_template != NULL) && (search->hostt != the_template)) || (search->irq != instance->irq) || (search == instance)); search = search->next); if (!search) { if (request_irq(instance->irq, do_AM53C974_intr, SA_SHIRQ, "AM53C974", instance)) { printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq); scsi_unregister(instance); return 0; } } else { printk("scsi%d: using interrupt handler previously installed for scsi%d\n", instance->host_no, search->host_no); } if (!the_template) { the_template = instance->hostt; first_instance = instance; }/* do hard reset */ AM53C974_write_8(CMDREG, CMDREG_RDEV); /* reset device */ udelay(5); AM53C974_write_8(CMDREG, CMDREG_NOP); AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */ udelay(10); AM53C974_config_after_reset(instance); mdelay(500); return (1);}/********************************************************************** Function : AM53C974_config_after_reset(struct Scsi_Host *instance) ** ** Purpose : initializes chip registers after reset ** ** Inputs : instance - which AM53C974 ** ** Returns : nothing ***********************************************************************/static void AM53C974_config_after_reset(struct Scsi_Host *instance){ AM53C974_local_declare(); AM53C974_setio(instance);/* clear SCSI FIFO */ AM53C974_write_8(CMDREG, CMDREG_CFIFO);/* configure device */ AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); AM53C974_write_8(STPREG, DEF_STP & STPREG_STP); AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); AM53C974_write_8(CLKFREG, DEF_CLKF & CLKFREG_MASK); AM53C974_write_8(CNTLREG1, (DEF_ETM << 7) | CNTLREG1_DISR | (DEF_PERE << 4) | instance->this_id); AM53C974_write_8(CNTLREG2, (DEF_ENF << 6)); AM53C974_write_8(CNTLREG3, (DEF_ADIDCHK << 7) | (DEF_FASTSCSI << 4) | (DEF_FASTCLK << 3)); AM53C974_write_8(CNTLREG4, (DEF_GLITCH << 6) | (DEF_PWD << 5) | (DEF_RAE << 3) | (DEF_RADE << 2) | CNTLREG4_RES);}/************************************************************************ Function : const char *AM53C974_info(struct Scsi_Host *instance) ** ** Purpose : return device driver information ** ** Inputs : instance - which AM53C974 ** ** Returns : info string *************************************************************************/const char *AM53C974_info(struct Scsi_Host *instance){ static char info[100]; sprintf(info, "AM53/79C974 PCscsi driver rev. %d.%d; host I/O address: 0x%lx; irq: %d\n", AM53C974_DRIVER_REVISION_MAJOR, AM53C974_DRIVER_REVISION_MINOR, instance->io_port, instance->irq); return (info);}/************************************************************************** * Function : int AM53C974_command (Scsi_Cmnd *SCpnt) ** ** Purpose : the unqueued SCSI command function, replaced by the ** AM53C974_queue_command function ** ** Inputs : SCpnt - pointer to command structure ** ** Returns :status, see hosts.h for details ****************************************************************************/int AM53C974_command(Scsi_Cmnd * SCpnt){ DEB(printk("AM53C974_command called\n")); return 0;}/*************************************************************************** Function : void initialize_SCp(Scsi_Cmnd *cmd) ** ** Purpose : initialize the saved data pointers for cmd to point to the ** start of the buffer. * * ** Inputs : cmd - Scsi_Cmnd structure to have pointers reset. ** ** Returns : nothing ***************************************************************************/static __inline__ void initialize_SCp(Scsi_Cmnd * cmd){ if (cmd->use_sg) { cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; cmd->SCp.ptr = (char *) cmd->request_buffer; cmd->SCp.this_residual = cmd->request_bufflen; }}/*************************************************************************** Function : run_main(void) ** ** Purpose : insure that the coroutine is running and will process our ** request. main_running is checked/set here (in an inline ** function rather than in AM53C974_main itself to reduce the ** chances of stack overflow. ** ** ** Inputs : none ** ** Returns : nothing ***************************************************************************/static __inline__ void run_main(void){ unsigned long flags; save_flags(flags); cli(); if (!main_running) { /* main_running is cleared in AM53C974_main once it can't do more work, and AM53C974_main exits with interrupts disabled. */ main_running = 1; AM53C974_main(); } restore_flags(flags);}/************************************************************************** * Function : int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))** Purpose : writes SCSI command into AM53C974 FIFO ** Inputs : cmd - SCSI command, done - function called on completion, with* a pointer to the command descriptor.* * Returns : status, see hosts.h for details** Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted.**************************************************************************/int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){ unsigned long flags; struct Scsi_Host *instance = cmd->host; struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; Scsi_Cmnd *tmp; save_flags(flags); cli(); DEB_QUEUE(printk(SEPARATOR_LINE)); DEB_QUEUE(printk("scsi%d: AM53C974_queue_command called\n", instance->host_no)); DEB_QUEUE(printk("cmd=%02x target=%02x lun=%02x bufflen=%d use_sg = %02x\n", cmd->cmnd[0], cmd->target, cmd->lun, cmd->request_bufflen, cmd->use_sg));/* We use the host_scribble field as a pointer to the next command in a queue */ cmd->host_scribble = NULL; cmd->scsi_done = done; cmd->result = 0; cmd->device->disconnect = 0;/* Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will * clear the contingent allegiance condition that exists and the * sense data is only guaranteed to be valid while the condition exists. */ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; } DEB_QUEUE(printk("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"));/* Run the coroutine if it isn't already running. */ run_main(); restore_flags(flags); return 0;}/************************************************************************** * Function : AM53C974_main (void) * * Purpose : AM53C974_main is a coroutine that runs as long as more work can * be done on the AM53C974 host adapters in a system. Both * AM53C974_queue_command() and AM53C974_intr() will try to start it * in case it is not running. * * NOTE : AM53C974_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. **************************************************************************/static void AM53C974_main(void){ AM53C974_local_declare(); unsigned long flags; Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance; struct AM53C974_hostdata *hostdata; 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 main_running to 0 and exit. */ save_flags(flags); cli(); /* Freeze request queues */ do { done = 1; for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { hostdata = (struct AM53C974_hostdata *) instance->hostdata; AM53C974_setio(instance); /* start to select target if we are not connected and not in the selection process */ if (!hostdata->connected && !hostdata->sel_cmd) { /* Search through the issue_queue for a command destined for a target that is not busy. */ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) { /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { REMOVE(prev, (Scsi_Cmnd *) (prev->host_scribble), tmp, (Scsi_Cmnd *) (tmp->host_scribble)); prev->host_scribble = tmp->host_scribble; } else { REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; } tmp->host_scribble = NULL; /* go into selection mode, disable reselection and wait for SO interrupt which will continue with the selection process */ hostdata->selecting = 1; hostdata->sel_cmd = tmp; AM53C974_write_8(CMDREG, CMDREG_DSR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -