aha152x.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,512 行 · 第 1/5 页
C
2,512 行
previous state, last state different from current state */ enum aha152x_state state, prevstate, laststate; int target; /* reconnecting target */ unsigned char syncrate[8]; /* current synchronous transfer agreements */ unsigned char syncneg[8]; /* 0: no negotiation; * 1: negotiation in progress; * 2: negotiation completed */ int cmd_i; /* number of sent bytes of current command */ int msgi_len; /* number of received message bytes */ unsigned char msgi[256]; /* received message bytes */ int msgo_i, msgo_len; /* number of sent bytes and length of current messages */ unsigned char msgo[256]; /* pending messages */ int data_len; /* number of sent/received bytes in dataphase */ unsigned long io_port0; unsigned long io_port1;#ifdef __ISAPNP__ struct pnp_dev *pnpdev;#endif};/* * host specific command extension * */struct aha152x_scdata { Scsi_Cmnd *next; /* next sc in queue */ struct semaphore *sem; /* semaphore to block on */};/* access macros for hostdata */#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)#define HOSTNO ((shpnt)->host_no)#define CURRENT_SC (HOSTDATA(shpnt)->current_SC)#define DONE_SC (HOSTDATA(shpnt)->done_SC)#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)#define QLOCK (HOSTDATA(shpnt)->lock)#define QLOCKER (HOSTDATA(shpnt)->locker)#define QLOCKERL (HOSTDATA(shpnt)->lockerl)#define STATE (HOSTDATA(shpnt)->state)#define PREVSTATE (HOSTDATA(shpnt)->prevstate)#define LASTSTATE (HOSTDATA(shpnt)->laststate)#define RECONN_TARGET (HOSTDATA(shpnt)->target)#define CMD_I (HOSTDATA(shpnt)->cmd_i)#define MSGO(i) (HOSTDATA(shpnt)->msgo[i])#define MSGO_I (HOSTDATA(shpnt)->msgo_i)#define MSGOLEN (HOSTDATA(shpnt)->msgo_len)#define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))#define MSGI(i) (HOSTDATA(shpnt)->msgi[i])#define MSGILEN (HOSTDATA(shpnt)->msgi_len)#define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))#define DATA_LEN (HOSTDATA(shpnt)->data_len)#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])#define DELAY (HOSTDATA(shpnt)->delay)#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans)#define TC1550 (HOSTDATA(shpnt)->tc1550)#define RECONNECT (HOSTDATA(shpnt)->reconnect)#define PARITY (HOSTDATA(shpnt)->parity)#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous)#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0)#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1)#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)#define SCNEXT(SCpnt) SCDATA(SCpnt)->next#define SCSEM(SCpnt) SCDATA(SCpnt)->sem#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))/* state handling */static void seldi_run(struct Scsi_Host *shpnt);static void seldo_run(struct Scsi_Host *shpnt);static void selto_run(struct Scsi_Host *shpnt);static void busfree_run(struct Scsi_Host *shpnt);static void msgo_init(struct Scsi_Host *shpnt);static void msgo_run(struct Scsi_Host *shpnt);static void msgo_end(struct Scsi_Host *shpnt);static void cmd_init(struct Scsi_Host *shpnt);static void cmd_run(struct Scsi_Host *shpnt);static void cmd_end(struct Scsi_Host *shpnt);static void datai_init(struct Scsi_Host *shpnt);static void datai_run(struct Scsi_Host *shpnt);static void datai_end(struct Scsi_Host *shpnt);static void datao_init(struct Scsi_Host *shpnt);static void datao_run(struct Scsi_Host *shpnt);static void datao_end(struct Scsi_Host *shpnt);static void status_run(struct Scsi_Host *shpnt);static void msgi_run(struct Scsi_Host *shpnt);static void msgi_end(struct Scsi_Host *shpnt);static void parerr_run(struct Scsi_Host *shpnt);static void rsti_run(struct Scsi_Host *shpnt);static void is_complete(struct Scsi_Host *shpnt);/* * driver states * */static struct { char *name; void (*init)(struct Scsi_Host *); void (*run)(struct Scsi_Host *); void (*end)(struct Scsi_Host *); int spio;} states[] = { { "idle", NULL, NULL, NULL, 0}, { "unknown", NULL, NULL, NULL, 0}, { "seldo", NULL, seldo_run, NULL, 0}, { "seldi", NULL, seldi_run, NULL, 0}, { "selto", NULL, selto_run, NULL, 0}, { "busfree", NULL, busfree_run, NULL, 0}, { "msgo", msgo_init, msgo_run, msgo_end, 1}, { "cmd", cmd_init, cmd_run, cmd_end, 1}, { "msgi", NULL, msgi_run, msgi_end, 1}, { "status", NULL, status_run, NULL, 1}, { "datai", datai_init, datai_run, datai_end, 0}, { "datao", datao_init, datao_run, datao_end, 0}, { "parerr", NULL, parerr_run, NULL, 0}, { "rsti", NULL, rsti_run, NULL, 0},};/* setup & interrupt */static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);static void reset_ports(struct Scsi_Host *shpnt);static void aha152x_error(struct Scsi_Host *shpnt, char *msg);static void done(struct Scsi_Host *shpnt, int error);/* diagnostics */static void disp_ports(struct Scsi_Host *shpnt);static void show_command(Scsi_Cmnd * ptr);static void show_queues(struct Scsi_Host *shpnt);static void disp_enintr(struct Scsi_Host *shpnt);/* * queue services: * */static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC){ Scsi_Cmnd *end; SCNEXT(new_SC) = NULL; if (!*SC) *SC = new_SC; else { for (end = *SC; SCNEXT(end); end = SCNEXT(end)) ; SCNEXT(end) = new_SC; }}static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC){ Scsi_Cmnd *ptr; ptr = *SC; if (ptr) { *SC = SCNEXT(*SC); SCNEXT(ptr)=NULL; } return ptr;}static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun){ Scsi_Cmnd *ptr, *prev; for (ptr = *SC, prev = NULL; ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); prev = ptr, ptr = SCNEXT(ptr)) ; if (ptr) { if (prev) SCNEXT(prev) = SCNEXT(ptr); else *SC = SCNEXT(ptr); SCNEXT(ptr)=NULL; } return ptr;}static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp){ Scsi_Cmnd *ptr, *prev; for (ptr = *SC, prev = NULL; ptr && SCp!=ptr; prev = ptr, ptr = SCNEXT(ptr)) ; if (ptr) { if (prev) SCNEXT(prev) = SCNEXT(ptr); else *SC = SCNEXT(ptr); SCNEXT(ptr)=NULL; } return ptr;}static inline struct Scsi_Host *lookup_irq(int irqno){ int i; for(i=0; i<ARRAY_SIZE(aha152x_host); i++) if(aha152x_host[i] && aha152x_host[i]->irq==irqno) return aha152x_host[i]; return NULL;}static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs){ struct Scsi_Host *shpnt = lookup_irq(irqno); if (!shpnt) { printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno); return IRQ_NONE; } HOSTDATA(shpnt)->swint++; SETPORT(DMACNTRL0, INTEN); return IRQ_HANDLED;}struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup){ struct Scsi_Host *shpnt; shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata)); if (!shpnt) { printk(KERN_ERR "aha152x: scsi_host_alloc failed\n"); return NULL; } /* need to have host registered before triggering any interrupt */ aha152x_host[registered_count] = shpnt; memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt)); shpnt->io_port = setup->io_port; shpnt->n_io_port = IO_RANGE; shpnt->irq = setup->irq; if (!setup->tc1550) { HOSTIOPORT0 = setup->io_port; HOSTIOPORT1 = setup->io_port; } else { HOSTIOPORT0 = setup->io_port+0x10; HOSTIOPORT1 = setup->io_port-0x10; } spin_lock_init(&QLOCK); RECONNECT = setup->reconnect; SYNCHRONOUS = setup->synchronous; PARITY = setup->parity; DELAY = setup->delay; EXT_TRANS = setup->ext_trans;#if defined(AHA152X_DEBUG) HOSTDATA(shpnt)->debug = setup->debug;#endif SETPORT(SCSIID, setup->scsiid << 4); shpnt->this_id = setup->scsiid; if (setup->reconnect) shpnt->can_queue = AHA152X_MAXQUEUE; /* RESET OUT */ printk("aha152x: resetting bus...\n"); SETPORT(SCSISEQ, SCSIRSTO); mdelay(256); SETPORT(SCSISEQ, 0); mdelay(DELAY); reset_ports(shpnt); printk(KERN_INFO "aha152x%d%s: " "vital data: rev=%x, " "io=0x%03lx (0x%03lx/0x%03lx), " "irq=%d, " "scsiid=%d, " "reconnect=%s, " "parity=%s, " "synchronous=%s, " "delay=%d, " "extended translation=%s\n", shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "", GETPORT(REV) & 0x7, shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, shpnt->irq, shpnt->this_id, RECONNECT ? "enabled" : "disabled", PARITY ? "enabled" : "disabled", SYNCHRONOUS ? "enabled" : "disabled", DELAY, EXT_TRANS ? "enabled" : "disabled"); /* not expecting any interrupts */ SETPORT(SIMODE0, 0); SETPORT(SIMODE1, 0); if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) { printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq); goto out_host_put; } HOSTDATA(shpnt)->swint = 0; printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no); mb(); SETPORT(DMACNTRL0, SWINT|INTEN); mdelay(1000); free_irq(shpnt->irq, shpnt); if (!HOSTDATA(shpnt)->swint) { if (TESTHI(DMASTAT, INTSTAT)) { printk("lost.\n"); } else { printk("failed.\n"); } SETPORT(DMACNTRL0, INTEN); printk(KERN_ERR "aha152x%d: irq %d possibly wrong. " "Please verify.\n", shpnt->host_no, shpnt->irq); goto out_host_put; } printk("ok.\n"); /* clear interrupts */ SETPORT(SSTAT0, 0x7f); SETPORT(SSTAT1, 0xef); if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) { printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq); goto out_host_put; } if( scsi_add_host(shpnt, NULL) ) { free_irq(shpnt->irq, shpnt); printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no); goto out_host_put; } scsi_scan_host(shpnt); registered_count++; return shpnt;out_host_put: aha152x_host[registered_count]=NULL; scsi_host_put(shpnt); return NULL;}void aha152x_release(struct Scsi_Host *shpnt){ if(!shpnt) return; if (shpnt->irq) free_irq(shpnt->irq, shpnt);#if !defined(PCMCIA) if (shpnt->io_port) release_region(shpnt->io_port, IO_RANGE);#endif#ifdef __ISAPNP__ if (HOSTDATA(shpnt)->pnpdev) pnp_device_detach(HOSTDATA(shpnt)->pnpdev);#endif scsi_remove_host(shpnt); scsi_host_put(shpnt);}/* * setup controller to generate interrupts depending * on current state (lock has to be acquired) * */ static int setup_expected_interrupts(struct Scsi_Host *shpnt){ if(CURRENT_SC) { CURRENT_SC->SCp.phase |= 1 << 16; if(CURRENT_SC->SCp.phase & selecting) { DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC)); SETPORT(SSTAT1, SELTO); SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); SETPORT(SIMODE1, ENSELTIMO); } else { DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : ""); SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); } } else if(STATE==seldi) { DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC)); SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); } else { DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n", CMDINFO(CURRENT_SC), DISCONNECTED_SC ? "(reselection)" : "", ISSUE_SC ? "(busfree)" : ""); SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); } if(!HOSTDATA(shpnt)->in_intr) SETBITS(DMACNTRL0, INTEN); return TESTHI(DMASTAT, INTSTAT);}/* * Queue a command and setup interrupts for a free bus. */static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *)){ struct Scsi_Host *shpnt = SCpnt->device->host; unsigned long flags;#if defined(AHA152X_DEBUG) if (HOSTDATA(shpnt)->debug & debug_queue) { printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=", CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); print_command(SCpnt->cmnd); }#endif SCpnt->scsi_done = done; SCpnt->resid = SCpnt->request_bufflen; SCpnt->SCp.phase = not_issued | phase; SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; SCpnt->SCp.have_data_in = 0; SCpnt->SCp.sent_command = 0; if(SCpnt->SCp.phase & (resetting|check_condition)) { if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) { printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt)); return FAILED; } } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?