📄 acsi.c
字号:
static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable){ unsigned long flags, paddr; int i;#ifdef NO_WRITE if (rwflag || *cmd == 0x0a) { printk( "ACSI: Write commands disabled!\n" ); return( 0 ); }#endif rwflag = rwflag ? 0x100 : 0; paddr = virt_to_phys( buffer ); acsi_delay_end(COMMAND_DELAY); DISABLE_IRQ(); save_flags(flags); cli(); /* Low on A1 */ dma_wd.dma_mode_status = 0x88 | rwflag; MFPDELAY(); /* set DMA address */ dma_wd.dma_lo = (unsigned char)paddr; paddr >>= 8; MFPDELAY(); dma_wd.dma_md = (unsigned char)paddr; paddr >>= 8; MFPDELAY(); if (ATARIHW_PRESENT(EXTD_DMA)) st_dma_ext_dmahi = (unsigned short)paddr; else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); restore_flags(flags); /* send the command bytes except the last */ for( i = 0; i < 5; ++i ) { DMA_LONG_WRITE( *cmd++, 0x8a | rwflag ); udelay(20); if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ } /* Clear FIFO and switch DMA to correct direction */ dma_wd.dma_mode_status = 0x92 | (rwflag ^ 0x100); MFPDELAY(); dma_wd.dma_mode_status = 0x92 | rwflag; MFPDELAY(); /* How many sectors for DMA */ dma_wd.fdc_acces_seccount = blocks; MFPDELAY(); /* send last command byte */ dma_wd.dma_mode_status = 0x8a | rwflag; MFPDELAY(); DMA_LONG_WRITE( *cmd++, 0x0a | rwflag ); if (enable) ENABLE_IRQ(); udelay(80); return( 1 );}/* * acsicmd_nodma() sends an ACSI command that requires no DMA. */int acsicmd_nodma( const char *cmd, int enable){ int i; acsi_delay_end(COMMAND_DELAY); DISABLE_IRQ(); /* send first command byte */ dma_wd.dma_mode_status = 0x88; MFPDELAY(); DMA_LONG_WRITE( *cmd++, 0x8a ); udelay(20); if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ /* send the intermediate command bytes */ for( i = 0; i < 4; ++i ) { DMA_LONG_WRITE( *cmd++, 0x8a ); udelay(20); if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ } /* send last command byte */ DMA_LONG_WRITE( *cmd++, 0x0a ); if (enable) ENABLE_IRQ(); udelay(80); return( 1 ); /* Note that the ACSI interrupt is still disabled after this * function. If you want to get the IRQ delivered, enable it manually! */}static int acsi_reqsense( char *buffer, int targ, int lun){ CMDSET_TARG_LUN( reqsense_cmd, targ, lun); if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); dma_cache_maintenance( virt_to_phys(buffer), 16, 0 ); return( 1 );} /* * ACSI status phase: get the status byte from the bus * * I've seen several times that a 0xff status is read, propably due to * a timing error. In this case, the procedure is repeated after the * next _IRQ edge. */int acsi_getstatus( void ){ int status; DISABLE_IRQ(); for(;;) { if (!acsi_wait_for_IRQ( 100 )) { acsi_delay_start(); return( -1 ); } dma_wd.dma_mode_status = 0x8a; MFPDELAY(); status = dma_wd.fdc_acces_seccount; if (status != 0xff) break;#ifdef DEBUG printk("ACSI: skipping 0xff status byte\n" );#endif udelay(40); acsi_wait_for_noIRQ( 20 ); } dma_wd.dma_mode_status = 0x80; udelay(40); acsi_wait_for_noIRQ( 20 ); acsi_delay_start(); return( status & 0x1f ); /* mask of the device# */}#if (defined(CONFIG_ATARI_SLM) || defined(CONFIG_ATARI_SLM_MODULE))/* Receive data in an extended status phase. Needed by SLM printer. */int acsi_extstatus( char *buffer, int cnt ){ int status; DISABLE_IRQ(); udelay(80); while( cnt-- > 0 ) { if (!acsi_wait_for_IRQ( 40 )) return( 0 ); dma_wd.dma_mode_status = 0x8a; MFPDELAY(); status = dma_wd.fdc_acces_seccount; MFPDELAY(); *buffer++ = status & 0xff; udelay(40); } return( 1 );}/* Finish an extended status phase */void acsi_end_extstatus( void ){ dma_wd.dma_mode_status = 0x80; udelay(40); acsi_wait_for_noIRQ( 20 ); acsi_delay_start();}/* Send data in an extended command phase */int acsi_extcmd( unsigned char *buffer, int cnt ){ while( cnt-- > 0 ) { DMA_LONG_WRITE( *buffer++, 0x8a ); udelay(20); if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ } return( 1 );}#endifstatic void acsi_print_error( const unsigned char *errblk, int dev ){ int atari_err, i, errcode; struct acsi_error *arr; atari_err = acsi_info[dev].old_atari_disk; if (atari_err) errcode = errblk[0] & 0x7f; else if ((errblk[0] & 0x70) == 0x70) errcode = errblk[2] & 0x0f; else errcode = errblk[0] & 0x0f; printk( KERN_ERR "ACSI error 0x%02x", errcode ); if (errblk[0] & 0x80) printk( " for sector %d", ((errblk[1] & 0x1f) << 16) | (errblk[2] << 8) | errblk[0] ); arr = atari_err ? atari_acsi_errors : scsi_acsi_errors; i = atari_err ? sizeof(atari_acsi_errors)/sizeof(*atari_acsi_errors) : sizeof(scsi_acsi_errors)/sizeof(*scsi_acsi_errors); for( --i; i >= 0; --i ) if (arr[i].code == errcode) break; if (i >= 0) printk( ": %s\n", arr[i].text );}/******************************************************************* * * ACSI interrupt routine * Test, if this is a ACSI interrupt and call the irq handler * Otherwise ignore this interrupt. * *******************************************************************/static void acsi_interrupt(int irq, void *data, struct pt_regs *fp ){ void (*acsi_irq_handler)(void) = DEVICE_INTR; DEVICE_INTR = NULL; CLEAR_TIMER(); if (!acsi_irq_handler) acsi_irq_handler = unexpected_acsi_interrupt; acsi_irq_handler();}/****************************************************************** * * The Interrupt handlers * *******************************************************************/static void unexpected_acsi_interrupt( void ){ printk( KERN_WARNING "Unexpected ACSI interrupt\n" );}/* This function is called in case of errors. Because we cannot reset * the ACSI bus or a single device, there is no other choice than * retrying several times :-( */static void bad_rw_intr( void ){ if (QUEUE_EMPTY) return; if (++CURRENT->errors >= MAX_ERRORS) end_request(0); /* Otherwise just retry */}static void read_intr( void ){ int status; status = acsi_getstatus(); if (status != 0) { int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); else { acsi_print_error( acsi_buffer, dev ); if (CARTRCH_STAT( dev, acsi_buffer )) acsi_info[dev].changed = 1; } ENABLE_IRQ(); bad_rw_intr(); redo_acsi_request(); return; } dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 ); if (CurrentBuffer == acsi_buffer) copy_from_acsibuffer(); do_end_requests(); redo_acsi_request();}static void write_intr(void){ int status; status = acsi_getstatus(); if (status != 0) { int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); else { acsi_print_error( acsi_buffer, dev ); if (CARTRCH_STAT( dev, acsi_buffer )) acsi_info[dev].changed = 1; } bad_rw_intr(); redo_acsi_request(); return; } do_end_requests(); redo_acsi_request();}static void acsi_times_out( unsigned long dummy ){ DISABLE_IRQ(); if (!DEVICE_INTR) return; DEVICE_INTR = NULL; printk( KERN_ERR "ACSI timeout\n" ); if (QUEUE_EMPTY) return; if (++CURRENT->errors >= MAX_ERRORS) {#ifdef DEBUG printk( KERN_ERR "ACSI: too many errors.\n" );#endif end_request(0); } redo_acsi_request();}/*********************************************************************** * * Scatter-gather utility functions * ***********************************************************************/static void copy_to_acsibuffer( void ){ int i; char *src, *dst; struct buffer_head *bh; src = CURRENT->buffer; dst = acsi_buffer; bh = CURRENT->bh; if (!bh) memcpy( dst, src, CurrentNSect*512 ); else for( i = 0; i < CurrentNReq; ++i ) { memcpy( dst, src, bh->b_size ); dst += bh->b_size; if ((bh = bh->b_reqnext)) src = bh->b_data; }}static void copy_from_acsibuffer( void ){ int i; char *src, *dst; struct buffer_head *bh; dst = CURRENT->buffer; src = acsi_buffer; bh = CURRENT->bh; if (!bh) memcpy( dst, src, CurrentNSect*512 ); else for( i = 0; i < CurrentNReq; ++i ) { memcpy( dst, src, bh->b_size ); src += bh->b_size; if ((bh = bh->b_reqnext)) dst = bh->b_data; }}static void do_end_requests( void ){ int i, n; if (!CURRENT->bh) { CURRENT->nr_sectors -= CurrentNSect; CURRENT->current_nr_sectors -= CurrentNSect; CURRENT->sector += CurrentNSect; if (CURRENT->nr_sectors == 0) end_request(1); } else { for( i = 0; i < CurrentNReq; ++i ) { n = CURRENT->bh->b_size >> 9; CURRENT->nr_sectors -= n; CURRENT->current_nr_sectors -= n; CURRENT->sector += n; end_request(1); } }}/*********************************************************************** * * do_acsi_request and friends * ***********************************************************************/static void do_acsi_request( request_queue_t * q ){ stdma_lock( acsi_interrupt, NULL ); redo_acsi_request();}static void redo_acsi_request( void ){ unsigned block, dev, target, lun, nsect; char *buffer; unsigned long pbuffer; struct buffer_head *bh; if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) { if (!DEVICE_INTR) { ENABLE_IRQ(); stdma_release(); } return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -