📄 qla1280.c
字号:
DRIVER_UNLOCK DEBUG(printk("RESET returning %d\n", result)); COMTRACE('r') LEAVE("qla1280_reset"); return( result );}/************************************************************************** * qla1200_biosparam * Return the disk geometry for the given SCSI device. **************************************************************************/intqla1280_biosparam(Disk *disk, kdev_t dev, int geom[]){ int heads, sectors, cylinders; heads = 64; sectors = 32; cylinders = disk->capacity / (heads * sectors); if (cylinders > 1024) { heads = 255; sectors = 63; cylinders = disk->capacity / (heads * sectors); /* if (cylinders > 1023) cylinders = 1023; */ } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return (0);}/************************************************************************** * qla1280_intr_handler * Handles the H/W interrupt **************************************************************************/void qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0;#endif scsi_qla_host_t *ha; u_short data; device_reg_t *reg; ENTER_INTR("qla1280_intr_handler"); COMTRACE('I') ha = (scsi_qla_host_t *) dev_id; if(!ha) { printk(KERN_INFO "scsi(): Interrupt with NULL host ptr\n"); COMTRACE('X') return; }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) spin_lock_irqsave(&io_request_lock, cpu_flags); if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags)) { COMTRACE('X') spin_unlock_irqrestore(&io_request_lock, cpu_flags); return; } ha->isr_count++; reg = ha->iobase; /* disable our interrupt. */ WRT_REG_WORD(®->ictrl, 0); data = qla1280_debounce_register(®->istatus); /* Check for pending interrupts. */ if ( !(data & RISC_INT) ) { /* spurious interrupts can happen legally */ DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); COMTRACE('X') } else qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); if (ha->done_q_first) qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); clear_bit(QLA1280_IN_ISR_BIT, &ha->flags); spin_unlock_irqrestore(&io_request_lock, cpu_flags);#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */ if( test_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags) ) { COMTRACE('X') printk(KERN_INFO "scsi(%d): Already in interrupt - returning \n", (int)ha->host_no); return; } set_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); ha->isr_count++; reg = ha->iobase; /* disable our interrupt. */ WRT_REG_WORD(®->ictrl, 0); data = qla1280_debounce_register(®->istatus); /* Check for pending interrupts. */ if ( !(data & RISC_INT) ) { /* spurious interrupts can happen legally */ DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); COMTRACE('X') } else qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); /* if no work to do then call the SCSI mid-level right away */ if( ha->done_q_first ) qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); /* Schedule the DPC routine */ if (ha->flags.isp_abort_needed || ha->flags.reset_marker || ha->done_q_first ) { ha->run_qla_bh.data = (void *) ha; ha->run_qla_bh.routine = qla1280_do_dpc; COMTRACE('P') schedule_task(&ha->run_qla_bh); ha->flags.dpc_sched = TRUE; } clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags);#endif /* enable our interrupt. */ WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); COMTRACE('i') LEAVE_INTR("qla1280_intr_handler");}/************************************************************************** * qla1280_do_dpc * * Description: * This routine is a task that is schedule by the interrupt handler * to perform the background processing for interrupts. We put it * on a task queue that is consumed whenever the scheduler runs; that's * so you can do anything (i.e. put the process to sleep etc). In fact, the * mid-level tries to sleep when it reaches the driver threshold * "host->can_queue". This can cause a panic if we were in our interrupt * code . **************************************************************************/static void qla1280_do_dpc(void *p){ scsi_qla_host_t *ha = (scsi_qla_host_t *) p;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0;#endif COMTRACE('p') #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) spin_lock_irqsave(&io_request_lock, cpu_flags);#endif if (ha->flags.isp_abort_needed) qla1280_abort_isp(ha); if (ha->flags.reset_marker) qla1280_rst_aen(ha); if (ha->done_q_first) qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); ha->flags.dpc_sched = FALSE;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) spin_unlock_irqrestore(&io_request_lock, cpu_flags);#endif}/************************************************************************** * qla1280_device_queue_depth * * Description: * Determines the queue depth for a given device. There are two ways * a queue depth can be obtained for a tagged queueing device. One * way is the default queue depth which is determined by whether * If it is defined, then it is used * as the default queue depth. Otherwise, we use either 4 or 8 as the * default queue depth (dependent on the number of hardware SCBs). **************************************************************************/STATIC void qla1280_device_queue_depth(scsi_qla_host_t *p, Scsi_Device *device){ int default_depth = 3; int bus = device->channel; int target = device->id; device->queue_depth = default_depth; if (device->tagged_supported && (p->bus_settings[bus].qtag_enables & (BIT_0 << target)) ) { device->tagged_queue = 1; device->current_tag = 0; device->queue_depth = p->bus_settings[bus].hiwat; /* device->queue_depth = 20; */ printk(KERN_INFO "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue depth %d.\n", (int)p->host_no, device->channel, device->id, device->lun, device->queue_depth); } qla12160_get_target_parameters(p, bus, target, device->lun);}/************************************************************************** * qla1280_select_queue_depth * * Sets the queue depth for each SCSI device hanging off the input * host adapter. We use a queue depth of 2 for devices that do not * support tagged queueing. **************************************************************************/STATIC voidqla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs){ Scsi_Device *device; scsi_qla_host_t *p = (scsi_qla_host_t *) host->hostdata; ENTER("qla1280_select_queue_depth"); for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) qla1280_device_queue_depth(p, device); } LEAVE("qla1280_select_queue_depth");}/*--------------------------**** Driver Support Routines ****--------------------------*/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)/* * mdelay * Delay in milliseconds * * Input: * milliseconds = delay */STATIC inline void mdelay(int milliseconds){ int i; for(i=0; i<milliseconds; i++) udelay(1000);}#endif/* * qla1280_done * Process completed commands. * * Input: * ha = adapter block pointer. * done_q_first = done queue first pointer. * done_q_last = done queue last pointer. */STATIC voidqla1280_done(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last){ srb_t *sp; scsi_lu_t *q; uint32_t b, t, l; Scsi_Cmnd *cmd;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0;#endif ENTER("qla1280_done"); COMTRACE('D') DRIVER_LOCK while (*done_q_first != NULL) { /* remove command from done list */ sp = *done_q_first; if (!(*done_q_first = sp->s_next)) *done_q_last = NULL; else (*done_q_first)->s_prev = NULL; cmd = sp->cmd; b = SCSI_BUS_32(cmd); t = SCSI_TCN_32(cmd); l = SCSI_LUN_32(cmd); q = LU_Q(ha, b, t, l); /* Decrement outstanding commands on device. */ if (q->q_outcnt) q->q_outcnt--; if (q->q_outcnt < ha->bus_settings[b].hiwat) { q->q_flag &= ~QLA1280_QBUSY; } q->resp_time += jiffies - sp->r_start; /* Lun bookkeeping information */ q->act_time += jiffies - sp->u_start; q->io_cnt++; if( sp->dir & BIT_5 ) q->r_cnt++; else q->w_cnt++; switch ( (CMD_RESULT(cmd)>>16)) { case DID_RESET: q->q_flag &= ~QLA1280_QRESET; /* Issue marker command. */ qla1280_marker(ha, b, t, 0, MK_SYNC_ID); break; case DID_ABORT: sp->flags &= ~SRB_ABORT_PENDING; sp->flags |= SRB_ABORTED; if (sp->flags & SRB_TIMEOUT) CMD_RESULT(sp->cmd)= DID_TIME_OUT << 16; break; default: break; } /* Call the mid-level driver interrupt handler */ CMD_HANDLE(sp->cmd) = (unsigned char *) 0; ha->actthreads--;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) sti(); (*(cmd)->scsi_done)(cmd); cli(); #else (*(cmd)->scsi_done)(cmd);#endif qla1280_next(ha, q, b); } DRIVER_UNLOCK COMTRACE('d') LEAVE("qla1280_done");}/* * Translates a ISP error to a Linux SCSI error */STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp){ int host_status = DID_ERROR;#if DEBUG_QLA1280_INTR STATIC char *reason[] = { "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR" };#endif /* DEBUG_QLA1280_INTR */ ENTER("qla1280_return_status");#if DEBUG_QLA1280_INTR /* DEBUG(printk("qla1280_return_status: compl status = 0x%04x\n", sts->c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -