📄 atari_scsi.c
字号:
*/ if (atari_dma_residual & 0x1ff) { DMA_PRINTK("SCSI DMA: DMA bug corrected, " "difference %ld bytes\n", 512 - (atari_dma_residual & 0x1ff)); atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff; } } tt_scsi_dma.dma_ctrl = 0; } /* If the DMA is finished, fetch the rest bytes and turn it off */ if (dma_stat & 0x40) { atari_dma_residual = 0; if ((dma_stat & 1) == 0) atari_scsi_fetch_restbytes(); tt_scsi_dma.dma_ctrl = 0; }#endif /* REAL_DMA */ NCR5380_intr (0, 0, 0);#if 0 /* To be sure the int is not masked */ atari_enable_irq( IRQ_TT_MFP_SCSI );#endif}static void scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp){#ifdef REAL_DMA int dma_stat; /* Turn off DMA and select sector counter register before * accessing the status register (Atari recommendation!) */ st_dma.dma_mode_status = 0x90; dma_stat = st_dma.dma_mode_status; /* Bit 0 indicates some error in the DMA process... don't know * what happened exactly (no further docu). */ if (!(dma_stat & 0x01)) { /* DMA error */ printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR()); } /* If the DMA was active, but now bit 1 is not clear, it is some * other 5380 interrupt that finishes the DMA transfer. We have to * calculate the number of residual bytes and give a warning if * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) */ if (atari_dma_active && (dma_stat & 0x02)) { unsigned long transferred; transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; /* The ST-DMA address is incremented in 2-byte steps, but the * data are written only in 16-byte chunks. If the number of * transferred bytes is not divisible by 16, the remainder is * lost somewhere in outer space. */ if (transferred & 15) printk(KERN_ERR "SCSI DMA error: %ld bytes lost in " "ST-DMA fifo\n", transferred & 15); atari_dma_residual = HOSTDATA_DMALEN - transferred; DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", atari_dma_residual); } else atari_dma_residual = 0; atari_dma_active = 0; if (atari_dma_orig_addr) { /* If the dribble buffer was used on a read operation, copy the DMA-ed * data to the original destination address. */ memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr), HOSTDATA_DMALEN - atari_dma_residual); atari_dma_orig_addr = NULL; }#endif /* REAL_DMA */ NCR5380_intr (0, 0, 0);}#ifdef REAL_DMAstatic void atari_scsi_fetch_restbytes( void ){ int nr; char *src, *dst; unsigned long phys_dst; /* fetch rest bytes in the DMA register */ phys_dst = SCSI_DMA_READ_P(dma_addr); nr = phys_dst & 3; if (nr) { /* there are 'nr' bytes left for the last long address before the DMA pointer */ phys_dst ^= nr; DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", nr, phys_dst); /* The content of the DMA pointer is a physical address! */ dst = phys_to_virt(phys_dst); DMA_PRINTK(" = virt addr %p\n", dst); for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) *dst++ = *src++; }}#endif /* REAL_DMA */static int falcon_got_lock = 0;static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);static int falcon_trying_lock = 0;static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);static int falcon_dont_release = 0;/* This function releases the lock on the DMA chip if there is no * connected command and the disconnected queue is empty. On * releasing, instances of falcon_get_lock are awoken, that put * themselves to sleep for fairness. They can now try to get the lock * again (but others waiting longer more probably will win). */static voidfalcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ){ unsigned long oldflags; if (IS_A_TT()) return; save_flags(oldflags); cli(); if (falcon_got_lock && !hostdata->disconnected_queue && !hostdata->issue_queue && !hostdata->connected) { if (falcon_dont_release) {#if 0 printk("WARNING: Lock release not allowed. Ignored\n");#endif restore_flags(oldflags); return; } falcon_got_lock = 0; stdma_release(); wake_up( &falcon_fairness_wait ); } restore_flags(oldflags);}/* This function manages the locking of the ST-DMA. * If the DMA isn't locked already for SCSI, it tries to lock it by * calling stdma_lock(). But if the DMA is locked by the SCSI code and * there are other drivers waiting for the chip, we do not issue the * command immediately but wait on 'falcon_fairness_queue'. We will be * waked up when the DMA is unlocked by some SCSI interrupt. After that * we try to get the lock again. * But we must be prepared that more than one instance of * falcon_get_lock() is waiting on the fairness queue. They should not * try all at once to call stdma_lock(), one is enough! For that, the * first one sets 'falcon_trying_lock', others that see that variable * set wait on the queue 'falcon_try_wait'. * Complicated, complicated.... Sigh... */static void falcon_get_lock( void ){ unsigned long oldflags; if (IS_A_TT()) return; save_flags(oldflags); cli(); while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) sleep_on( &falcon_fairness_wait ); while (!falcon_got_lock) { if (in_interrupt()) panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); if (!falcon_trying_lock) { falcon_trying_lock = 1; stdma_lock(scsi_falcon_intr, NULL); falcon_got_lock = 1; falcon_trying_lock = 0; wake_up( &falcon_try_wait ); } else { sleep_on( &falcon_try_wait ); } } restore_flags(oldflags); if (!falcon_got_lock) panic("Falcon SCSI: someone stole the lock :-(\n");}/* This is the wrapper function for NCR5380_queue_command(). It just * tries to get the lock on the ST-DMA (see above) and then calls the * original function. */#if 0int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)){ /* falcon_get_lock(); * ++guenther: moved to NCR5380_queue_command() to prevent * race condition, see there for an explanation. */ return( NCR5380_queue_command( cmd, done ) );}#endifint atari_scsi_detect (Scsi_Host_Template *host){ static int called = 0; struct Scsi_Host *instance; if (!MACH_IS_ATARI || (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || called) return( 0 ); host->proc_name = "Atari"; atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read : atari_scsi_falcon_reg_read; atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write : atari_scsi_falcon_reg_write; /* setup variables */ host->can_queue = (setup_can_queue > 0) ? setup_can_queue : IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE; host->cmd_per_lun = (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN; /* Force sg_tablesize to 0 on a Falcon! */ host->sg_tablesize = !IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE : (setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE; if (setup_hostid >= 0) host->this_id = setup_hostid; else { /* use 7 as default */ host->this_id = 7; /* Test if a host id is set in the NVRam */ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) { unsigned char b = nvram_read_byte( 14 ); /* Arbitration enabled? (for TOS) If yes, use configured host ID */ if (b & 0x80) host->this_id = b & 7; } }#ifdef SUPPORT_TAGS if (setup_use_tagged_queuing < 0) setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;#endif#ifdef REAL_DMA /* If running on a Falcon and if there's TT-Ram (i.e., more than one * memory block, since there's always ST-Ram in a Falcon), then allocate a * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative * Ram. */ if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); if (!atari_dma_buffer) { printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " "double buffer\n" ); return( 0 ); } atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer ); atari_dma_orig_addr = 0; }#endif instance = scsi_register (host, sizeof (struct NCR5380_hostdata)); if(instance == NULL) { atari_stram_free(atari_dma_buffer); atari_dma_buffer = 0; return 0; } atari_scsi_host = instance; /* Set irq to 0, to avoid that the mid-level code disables our interrupt * during queue_command calls. This is completely unnecessary, and even * worse causes bad problems on the Falcon, where the int is shared with * IDE and floppy! */ instance->irq = 0;#ifdef CONFIG_ATARI_SCSI_RESET_BOOT atari_scsi_reset_boot();#endif NCR5380_init (instance, 0); if (IS_A_TT()) { /* This int is actually "pseudo-slow", i.e. it acts like a slow * interrupt after having cleared the pending flag for the DMA * interrupt. */ request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW, "SCSI NCR5380", scsi_tt_intr); tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */#ifdef REAL_DMA tt_scsi_dma.dma_ctrl = 0; atari_dma_residual = 0;#endif /* REAL_DMA */#ifdef REAL_DMA#ifdef CONFIG_TT_DMA_EMUL if (MACH_IS_HADES) { request_irq(IRQ_AUTO_2, hades_dma_emulator, IRQ_TYPE_PRIO, "Hades DMA emulator", hades_dma_emulator); }#endif if (MACH_IS_MEDUSA || MACH_IS_HADES) { /* While the read overruns (described by Drew Eckhardt in * NCR5380.c) never happened on TTs, they do in fact on the Medusa * (This was the cause why SCSI didn't work right for so long * there.) Since handling the overruns slows down a bit, I turned * the #ifdef's into a runtime condition. * * In principle it should be sufficient to do max. 1 byte with * PIO, but there is another problem on the Medusa with the DMA * rest data register. So 'atari_read_overruns' is currently set * to 4 to avoid having transfers that aren't a multiple of 4. If * the rest data bug is fixed, this can be lowered to 1. */ atari_read_overruns = 4; }#endif } else { /* ! IS_A_TT */ /* Nothing to do for the interrupt: the ST-DMA is initialized * already by atari_init_INTS() */#ifdef REAL_DMA atari_dma_residual = 0; atari_dma_active = 0; atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000);#endif } printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "#ifdef SUPPORT_TAGS "TAGGED-QUEUING=%s "#endif "HOSTID=%d", instance->host_no, instance->hostt->can_queue, instance->hostt->cmd_per_lun, instance->hostt->sg_tablesize,#ifdef SUPPORT_TAGS setup_use_tagged_queuing ? "yes" : "no",#endif instance->hostt->this_id ); NCR5380_print_options (instance); printk ("\n"); called = 1; return( 1 );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -