/*======================================================================/ This driver for the Qvision SCSI-3 card This driver referred some parts of following code. mps110_cs.c: qlogic pcmcia scsi driver written by N.Katayama (kata-n@po.iijnet.or.jp) This software may be used and distributed according to the terms of the GNU Public License. Copyright (c) 1998 Qvision. All rights reserved. ======================================================================*/ /*********************************************************************** Quantam LIGHTNING 365S NEC D3856(TEXA STARION 260) SAMSUNG WN3432U(I/O DATA HDVS-U4.3G) FUJITU M2614S(TEXA STARION 120LB) IBM DPES-31080 Teac CD-56S (Teac CD-600S ?) MEDIAVIS CDR-H93MV (TAXAN TS-CD 200) NEC CD-ROM DRIVE:501 (I/O DATA CDG SX-4) PD-1 LF-1000 (Panasonic LF-1000) (I/O DATA CDG TX-4) ***********************************************************************/ #include #include #ifdef MODULE #define init_ninja3_cs init_module #endif #include #include #include #include #include #include #include #include #include #ifdef GET_SCSI_INFO #if (LINUX_VERSION_CODE >= VERSION(1,3,98)) #include #else #include #endif #include #endif #include BLK_DEV_HDR #include "drivers/scsi/scsi.h" #include "drivers/scsi/hosts.h" #if (LINUX_VERSION_CODE >= VERSION(1,3,98)) #include #else #include "drivers/scsi/scsi_ioctl.h" #endif #include #include #include #include #include #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; static char *version = "ninja3_cs.c 0.1 (Workbit)"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) #endif /*====================================================================*/ /* typedef struct dev_node_t { char dev_name[8]; u_short major, minor; struct dev_node_t *next; } dev_node_t; */ typedef struct scsi_info_t { int ndev; dev_node_t node[8]; } scsi_info_t; static void ninja3_release(u_long arg); static int ninja3_event(event_t event, int priority, event_callback_args_t *args); static dev_link_t *ninja3_attach(void); static void ninja3_detach(dev_link_t *); static void ninja3_interrupt( void * ); /*static void ninja3_interrupt2 IRQ(int irq,void *dev_id,struct pt_regs *regs);*/ /*----------------------------------------------------------------*/ #include #if (LINUX_VERSION_CODE > VERSION(1,2,13)) #include /* to get disk capacity */ #endif #include #include #include "drivers/scsi/sd.h" #include #if (LINUX_VERSION_CODE > VERSION(1,2,13)) /* PROC_SCSI_SCSI = proc.fs.h*/ struct proc_dir_entry proc_scsi_ninja3 = { PROC_SCSI_SCSI, 6, "ninja3", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #endif /*====================================================================*/ /* Parameters that can be set with 'insmod' */ /* Bit map of interrupts to choose from */ /* This driver never use IRQ */ static u_long irq_mask = 0xfff0; /* if you not use MO, set fast_pio = 1 and sg_tablesize = 64 */ /*static int fast_pio = 1;*/ static int sg_tablesize = SG_NONE/*SG_ALL*/; static int Owattayo = 1; /* 0713 ORESAMA atode*/ /*----------------------------------------------------------------*/ /* driver state info, local to driver */ static int mbase = 0; /* Port */ static int minitid; /* initiator ID */ static int mabort; /* Flag to cause an abort */ static int mpirq = -1; /* IRQ being used */ static char minfo[80]; /* description */ static Scsi_Cmnd *mpcmd; /* current command being processed */ /*static struct tq_struct mps_tq = {0,0,ninja3_interrupt,NULL};*/ /*include\linux\tqueue.h(42): struct tq_struct*/ static struct tq_struct mps_tq = {0,0,ninja3_interrupt,NULL}; /* task queue entry */ int ninja3_detect(Scsi_Host_Template * ); const char * ninja3_info(struct Scsi_Host *); int ninja3_command(Scsi_Cmnd *); int ninja3_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int ninja3_abort(Scsi_Cmnd *); int ninja3_reset(Scsi_Cmnd *); #if (LINUX_VERSION_CODE > VERSION(1,2,13)) int ninja3_biosparam(Disk * , kdev_t, int []); #else int ninja3_biosparam(Disk * , int, int []); #endif #define NINJA3 { \ /* next */ NULL, \ /* usage_count */ NULL, \ /* proc_dir */ NULL, \ /* proc_info */ NULL, \ /* name */ NULL, \ /* detect */ ninja3_detect, \ /* release */ NULL, \ /* info */ ninja3_info, \ /* command */ ninja3_command, \ /* queuecommand */ ninja3_queuecommand, \ /* abort */ NULL/*ninja3_abort*/, \ /* reset */ ninja3_reset, \ /* slave_attach */ NULL, \ /* bios_param */ /*ninja3_biosparam*/NULL, \ /* can_queue */ 1, \ /* this_id */ -1, \ /* sg_tablesize */ SG_NONE /* SG_ALL */, \ /* cmd_per_lun */ 1, \ /* present */ 0, \ /* unchecked_isa_dma */ 0, \ DISABLE_CLUSTERING \ } static Scsi_Host_Template driver_template = NINJA3; static dev_link_t *dev_list = NULL; static dev_info_t dev_info = "nin_cs"; #ifdef USE_SLEEP_WAKE struct wait_queue *read_wait = NULL; #endif /* USE_SLEEP_WAKE */ /* ds.h typedef struct dev_link_t { dev_node_t *dev; u_int state, open; struct wait_queue *pending; struct timer_list release; client_handle_t handle; io_req_t io; irq_req_t irq; config_req_t conf; window_handle_t win; void *priv; struct dev_link_t *next; } dev_link_t; */ /***********************************************************/ #include "nin_cs.h" #define NNIN 2 static PSPECIFIC_LU_EXTENSION table[7][10]; static nin_softc nin_data[NNIN]; PSPECIFIC_LU_EXTENSION ScsiPortGetLogicalUnit(unsigned char TargetId,unsigned char Lun) { if (!table[TargetId][Lun]) { table[TargetId][Lun] = kmalloc(sizeof(SPECIFIC_LU_EXTENSION),GFP_BUFFER); /* scsi_malloc(sizeof(SPECIFIC_LU_EXTENSION));*/ } return table[TargetId][Lun]; } void ScsiPortFreeLogicalUnit(unsigned char TargetId,unsigned char Lun) { if (table[TargetId][Lun]) { kfree( table[TargetId][Lun]); /* free( table[TargetId][Lun] , M_DEVBUF);*/ table[TargetId][Lun] = 0; } } u_char Ns3FifoTest( int unit,IN PFIFO_TEST pTestMode) { TRANSFER_MODE saveMode; saveMode.TransferGo = 1; saveMode.FifoTest_Braind = 0; saveMode.MemMap8 = 0; saveMode.AdrData24 = 0; saveMode.MemMap16_32 = 0; saveMode.IO8 = 0; saveMode.IO16_32 = 1; /* ((PTRANSFER_MODE)&pSaveMode)->TransferGo = 1; ((PTRANSFER_MODE)&pSaveMode)->FifoTest_Braind = 0; ((PTRANSFER_MODE)&pSaveMode)->IO8 = 0; ((PTRANSFER_MODE)&pSaveMode)->IO16_32 = 1; return(SaveMode[0]); */ return(*((u_char *)(&saveMode))); } void Ns3ResetScsiBus( pnin_softc DevExt ) { PSPECIFIC_TARGET_EXTENSION targetState; u_long i; unsigned long flags; u_char dataByte; int baseAddress = DevExt->BaseAddress; baseAddress = mbase; save_flags( flags ); cli(); if (DevExt->DmaPending == TRUE) { DevExt->DmaPending = FALSE; } DevExt->InterruptPending = FALSE; /**/ SCSI_IRQ_CONTROL(baseAddress, 0xff); /* IRQ all Mssk & clear*/ /* // RESET SCSI bus. // */ dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->ScsiRst = 1; SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte); /* SCSI RST On !*/ udelay(RESET_HOLD_TIME); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiRst = 0; SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte); /* SCSI RST Off !*/ /* dummy read for SCSI RST IRQ/Phase Change */ for ( i= 0; i < 5; i++) { SCSI_READ(baseAddress,IRQPHASESENCE); } /* Set unsyncronus 5MB*/ for (i = 0; i < 7; i++) { targetState = &DevExt->TargetState[i]; /* Get pointer*/ targetState->TargetFlags &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE; targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; } #ifdef USE_IRQ_MASK SCSI_IRQ_CONTROL(baseAddress, 0xff); /* IRQ mask & clear*/ DevExt->IrqMaskData = 0xff; #else SCSI_IRQ_CONTROL(baseAddress, 0x0f); /* IRQ mask & clear*/ DevExt->IrqMaskData = 0x0f; #endif /* USE_IRQ_MASK */ udelay(RESET_RECOVER_TIME); restore_flags( flags ); } /*----------------------------------------------------------------*/ /* global functions */ /*----------------------------------------------------------------*/ int ninja3_precommand( PSPECIFIC_LU_EXTENSION *luExt, pnin_softc devExt, Scsi_Cmnd * Srb) { sti(); /* ** Determine the logical unit that this request is for. */ mabort = 0; (*luExt) = ScsiPortGetLogicalUnit( /* devExt->PathId, */ Srb->target, Srb->lun); if( !(*luExt) ) { /* Srb->error = XS_DRIVER_STUFFUP;*/ Srb->result = DID_ERROR << 16;/*XS_DRIVER_STUFFUP;*/ return FALSE; /*TRY_AGAIN_LATER;*/ } /* fuckin cable is too heat...*/ /* if ( !devExt->ScsiCable ) { Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT; ScsiPortNotification(RequestComplete,(void *) devExt,Srb); ScsiPortNotification(NextRequest,devExt,NULL); break; } */ /* ** Setup the context for this target/lun. */ (*luExt)->ActiveCommand = Srb; (*luExt)->SavedDataPointer = Srb->request_buffer;/*data;*/ (*luExt)->SavedDataLength = Srb->request_bufflen;/*datalen;*/ (*luExt)->PhaseWaitCounter = 0; devExt->ScsiState = SC_SELECT; return TRUE; } /*ninja3_precommand end*/ #ifdef DBG_SHOWCOMMAND static void show_command(Scsi_Cmnd *ptr); #endif /* DBG_SHOWCOMMAND */ int ninja3_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { PSPECIFIC_LU_EXTENSION luExtension; pnin_softc DevExt = &nin_data[0]; unsigned long flags; /* sti(); 0713 */ if( !Owattayo ) { return 0; } /* ORESAMA if( !Owattayo ) return 0; */ cmd->scsi_done = done; if( cmd->target == minitid ) { cmd->result = DID_BAD_TARGET << 16; mpcmd = NULL; done(cmd); return 0; } mpcmd = cmd; if( !ninja3_precommand(&luExtension,DevExt,cmd) ) { return cmd->result; } Ns3StartExecution(DevExt, luExtension, cmd); #ifndef USE_SELECTSAVEFLAG save_flags(flags); cli(); #endif /* USE_SELECTSAVEFLAG */ Ns3Select(DevExt,cmd); #ifdef USE_IRQ_MASK /* 0704 */ /* Timer IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 1; /* SCSI IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0; SCSI_IRQ_CONTROL(DevExt->BaseAddress, DevExt->IrqMaskData); #endif /* USE_IRQ_MASK */ #ifndef USE_SELECTSAVEFLAG restore_flags(flags); #endif /* USE_SELECTSAVEFLAG */ #ifndef USE_IRQ_HANDLE_PRESENT queue_task(&mps_tq,&tq_scheduler); #endif return 0; } int ninja3_command(Scsi_Cmnd * Srb) { PSPECIFIC_LU_EXTENSION luExtension; pnin_softc deviceExtension = &nin_data[0]; /* sti();*/ #ifdef DBG_SHOWCOMMAND show_command(Srb); #endif /* DBG_SHOWCOMMAND */ if (mabort) { Ns3DebugPrint(0x20,(KERN_DEBUG "ninja3_command DID_ABORT : DID_RESET\n")); return (mabort == 1 ? DID_ABORT : DID_RESET); } if( !ninja3_precommand(&luExtension,deviceExtension,Srb) ) { return Srb->result; } /* Initiate a SCSI request. */ Ns3StartExecution(deviceExtension, luExtension, Srb); if ( Ns3Select(deviceExtension,Srb) ) Ns3IrqPolling ( deviceExtension->unit ); return Srb->result; } /* end nin_scsi_cmd()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3StartExecution // // Routine Description: // // This routine will start the execution of a SCSI request. // // Arguments: // // DevExt - Device adapter context pointer. // LuExtension - The logical unit specific information. // Srb - The Srb command to execute. // // Return Value: // // None. // //----------------------------------------------------------------------- */ void Ns3StartExecution( IN pnin_softc DevExt, IN PSPECIFIC_LU_EXTENSION LuExtension, IN Scsi_Cmnd *Srb ) { PSPECIFIC_TARGET_EXTENSION targetState; if ((Srb->cmnd[1] >> 5) != Srb->lun) { Srb->cmnd[1] &= 0x1f; Srb->cmnd[1] |= (Srb->lun << 5); } DevExt->TargetId = Srb->target; /* Setup the context for this adapter. */ DevExt->ActiveUnit = LuExtension; DevExt->CurDataPointer = DevExt->ActiveUnit->SavedDataPointer; DevExt->CurDataLength = DevExt->ActiveUnit->SavedDataLength; /* Set TargetState Ns3MessageDecode */ DevExt->TargetId = Srb->target; targetState = &DevExt->TargetState[Srb->target]; /* // // Create the identify command. // */ /* #define MSG_IDENTIFY(lun) (0xc0 | ((lun) & 0x7)) */ /* DevExt->AdapterOption = OPT_NON_DISCONECT; 0605 */ /* NOT supported DISCONECT */ if ( /* (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) || */ (DevExt->AdapterOption & OPT_NON_DISCONECT) ) { DevExt->MessageBuffer[0] = MSG_IDENTIFYFLAG | Srb->lun; } else { DevExt->MessageBuffer[0] = MSG_IDENTIFYFLAG_WITH_DISCON | Srb->lun; } DevExt->MessageCount = 1; /* // Make SyncMessage if donot Sync Nego */ /* #define INQUIRY 0x12 scsi_all.h */ if (!(targetState->TargetFlags & PD_SYNCHRONOUS_NEGOTIATION_DONE ) && !(targetState->TargetFlags & PD_DO_NOT_NEGOTIATE) && (Srb->cmnd[0] != INQUIRY) /* INQUIRY:Don't Sync Nego */ ) { /* Sync message exchange [sync]*/ DevExt->MessageCount = 6; /* extended message out */ DevExt->MessageBuffer[1] = MSG_EXTENDED; /* length */ DevExt->MessageBuffer[2] = MSG_EXT_SDTR_LEN; /* extended message out command */ DevExt->MessageBuffer[3] = SCSIMESS_SYNCHRONOUS_DATA_REQ; #ifdef ULTRA DevExt->MessageBuffer[4] = DevExt->SynchronousPeriod; #else /* Transfer interval 100n = 10M ByteS */ DevExt->MessageBuffer[4] = SYNCHRONOUS_PERIOD; #endif DevExt->MessageBuffer[5] = SYNCHRONOUS_OFFSET; targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_SYNCHRONOUS_TRANSFER_SENT; DevExt->MessageCount = 1; /* ORESAMA 0629 */ } } /* end Ns3StartExecution()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3IrqPolling // // Routine Description: // // Interrupt Polling // /// //-----------------------------------------------------------------------*/ void Ns3IrqPolling ( int unit ) { pnin_softc DevExt = &(nin_data[unit]); int i; i = INT_POLL_SEL; while (i > 0 ) { if(Owattayo) { /* 0704 */ break; } if ( SCSI_IRQ_MONITOR(DevExt->BaseAddress) & 0xb ) /* 0706 */ { ninintr( unit ); break; } /* loop interval 530CS-133MHz : 4.5us */ udelay(5); /* udelay -> udelay */ i--; } #ifdef USE_IRQ_MASK /* Timer IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 1; /* SCSI IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0; SCSI_IRQ_CONTROL(DevExt->BaseAddress, DevExt->IrqMaskData); #endif /* USE_IRQ_MASK */ } /* //----------------------------------------------------------------------- // Routine Name: // // ninintr // // Routine Description: // // This routine handles the interrupts for the Ns3. The intention is to // quickly determine the cause of the interrupt, clear the interrupt, and // setup to process the SCSI command that is affected by the // interrupt. // // Arguments: // // Context - Device adapter context pointer. // // Return Value: // // TRUE indicates that the interrupt was from this Ns3 adapter, // FALSE indicates that this interrupt was NOT from us. // //----------------------------------------------------------------------- // boolean -> void */ void ninintr( int unit ) { long i; pnin_softc DevExt = &(nin_data[unit]); int baseAddress = DevExt->BaseAddress; IRQ_STATUS IntIrqStatus; IRQ_PHASE_SENSE IntIrqPhase; unsigned char dataByte; char TargetId; PSPECIFIC_TARGET_EXTENSION targetState; *((unsigned char *) &IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress); dataByte = 0; #ifdef USE_IRQ_MASK ((PIRQ_CONTROLP)&dataByte)->ExtIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->FifoIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->TimerIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->ScsiIrqMask = 1; #endif /* USE_IRQ_MASK */ SCSI_IRQ_CONTROL(baseAddress, dataByte); /* // IRQ All mask*/ IntEntry: /* from nin_unload */ if ( *((unsigned char *) &IntIrqStatus) == 0xff ) { /* DevExt->ActiveUnit->ActiveCommand->SrbStatus = SRB_STATUS_NO_DEVICE; */ Ns3NotifyCompletion(DevExt, DID_ERROR); DevExt->ScsiState = SC_BUSFREE; DevExt->IntWait = FALSE; return; /* TRUE;*/ } DevExt->InterruptPending = FALSE; /* // --- Timer interrupt? --- */ if ( IntIrqStatus.TimerIrqStatus ) { dataByte = 0xf0; ((PIRQ_CONTROLP)&dataByte)->TimerIrqClear = 1; /* Timer IRQ Clear*/ SCSI_IRQ_CONTROL(DevExt->BaseAddress, dataByte); if ( DevExt->TimerCount != 0 ) { /* Next TIMER START*/ SCSI_WRITE(DevExt->BaseAddress, TIMERCOUNT, DevExt->TimerCycle); DevExt->TimerCount--; } } /* // ---- SCSI IRQ ? ---- */ if ( IntIrqStatus.ScsiIrqStatus ) { *((unsigned char *)&IntIrqPhase) = SCSI_READ(baseAddress, IRQPHASESENCE); /* //---- ReSelection IRQ ? ---- */ if (IntIrqPhase.ReselectIrq) { TargetId =(unsigned char)(SCSI_READ(baseAddress, RESELECTID) & 0x7f); i = 0xffffffff; while ( TargetId > 0 ) { i++; TargetId = TargetId >> 1; } DevExt->TargetId = i; DevExt->TargetLun = DevExt->ActiveUnit->ActiveCommand->lun; do { dataByte = SCSI_READ(baseAddress, SCSIBUSMON); } while ( ((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_SEL ); /* SEL off ?*/ dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiBSY = 0; /* BUSY Off !*/ SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; /* AckEnb , AutoDirection ON !*/ ((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1; /* ( Not same time in BUSY off)*/ SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* set Sync-parameter*/ targetState = &DevExt->TargetState[DevExt->TargetId]; dataByte = 0; ((PSYNC_REG)&dataByte)->SyncPeriod = targetState->SynchronousPeriod; ((PSYNC_REG)&dataByte)->SyncOffset = targetState->SynchronousOffset; SCSI_WRITE(baseAddress, SYNCREG,dataByte); SCSI_WRITE(baseAddress, ACKWIDTH, targetState->AckWidth); /* Clear transfer clear*/ dataByte = 0; ((PPOINTER_CLEAR)&dataByte)->PointerClear = 1; ((PPOINTER_CLEAR)&dataByte)->AckCounterClear = 1; ((PPOINTER_CLEAR)&dataByte)->ReqCounterClear = 1; ((PPOINTER_CLEAR)&dataByte)->HostCounterClear = 1; SCSI_WRITE(baseAddress, POINTERCLR, dataByte); /* LUN isn't defined, not use LunExtension... wait for Message IN */ DevExt->ScsiState = SC_RESELECT; goto IntEnd; } /* --- SCSI RESET Irq ?---- */ if ( IntIrqPhase.ScsiResetIrq ) { /* Set unsync 5mb */ for (i = 0; i < 7; i++) { targetState = &DevExt->TargetState[i]; targetState->TargetFlags &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE; targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; } goto IntEnd; } /* --- Phase Change Interrupt ? --- */ if ( IntIrqPhase.PhaseChgIrq ) { Ns3RunPhase(DevExt, IntIrqPhase ); goto IntEnd; } } /* ---- FIFO Interrupt ? ---- */ if ( IntIrqStatus.FifoIrqStatus ) { /* Interrupt Clear*/ *((unsigned char *) &IntIrqPhase) = SCSI_READ(baseAddress, IRQPHASESENCE); /* Still nokori ga aru ?*/ if ( DevExt->CurDataLength ) { /* before Phase*/ if ( DevExt->ScsiPrePhase == BP_DATA_IN) Ns3DataInPhase(DevExt); else if (DevExt->ScsiPrePhase == BP_DATA_OUT) Ns3DataOutPhase(DevExt); } /*PhaseChange same time に発生 ?*/ if ( IntIrqPhase.PhaseChgIrq ) { Ns3RunPhase(DevExt, IntIrqPhase ); } goto IntEnd; } IntEnd: #ifdef USE_INTENTRY if ( !DevExt->IntWait ) { *((unsigned char *) &IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( *((unsigned char *)&IntIrqStatus) & 0xf ) { goto IntEntry;/* INT */ /* l.434 */ } } else { int polltimes; #ifdef USE_WRITE_SPECIAL if(DevExt->ActiveUnit->ActiveCommand->cmnd[0] == 0x0a) { /* 10000 -> 100 ORESAMA 0703 */ polltimes = INT_POLL_IRQ * 100; }else { polltimes = INT_POLL_IRQ; } #else polltimes = INT_POLL_IRQ; #endif /* USE_WRITE_SPECIAL */ for ( i = 0; i< polltimes; i++) { *((unsigned char *)&IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( *((unsigned char *)&IntIrqStatus) & 0x0f ) { goto IntEntry;/* INT */ /* l.434 */ } udelay(5); } } #endif /* USE_INTENTRY */ /* --- Reverse IRQ MASK MODE ---- */ #ifdef USE_IRQ_MASK SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData); #endif /* USE_IRQ_MASK */ DevExt->IntWait = TRUE; return ; /* TRUE;*/ } /* end ninintr()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3Select // // Routine Description: // // Perform selection process on SCSI bus. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // TRUE : Select Success /// //----------------------------------------------------------------------- */ boolean Ns3Select( IN pnin_softc DevExt ,Scsi_Cmnd *srb) { PSPECIFIC_TARGET_EXTENSION targetState; int baseAddress = DevExt->BaseAddress; unsigned char cdbLength = COMMAND_SIZE(srb->cmnd[0]);/*srb->cmdlen;*/ unsigned char *cdb = srb->cmnd; /*srb->cmd->bytes; srb->cmd;*/ unsigned char BusyByte, dataByte, AtnByte; #ifdef USE_SELECTSAVEFLAG unsigned long flags; #endif /* USE_SELECTSAVEFLAG */ AtnByte = 0; ((PSCSI_BUS_CONTROL)&AtnByte)->ScsiATN = 1; if ( DevExt->AdapterOption & OPT_NO_ATN ) ((PSCSI_BUS_CONTROL)&AtnByte)->ScsiATN = 0; #ifdef USE_SELECTSAVEFLAG save_flags(flags); cli(); #endif /* USE_SELECTSAVEFLAG */ /* --- Didable all interrupt */ dataByte = 0; #ifdef USE_IRQ_MASK ((PIRQ_CONTROLP)&dataByte)->FifoIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->TimerIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->ExtIrqMask = 1; ((PIRQ_CONTROLP)&dataByte)->ScsiIrqMask = 1; SCSI_IRQ_CONTROL(baseAddress, dataByte); #endif /* USE_IRQ_MASK */ DevExt->IrqMaskData = dataByte; /* --- CDB -> COMMAND FIFO --- INITIATOR -> target */ dataByte = 0; ((PCOMMAND_CONTROL)&dataByte)->ClrCommandPointer = 1; SCSI_WRITE(baseAddress,COMMANDCTRL, dataByte); /* CDB FIFO counter Clear*/ /* cdb <- srb <- DevExt->ActiveUnit->ActiveCommand; */ #ifdef DBG_SHOWCOMMAND show_command(srb); #endif /* DBG_SHOWCOMMAND */ /* cdbLength--; cdbLength - 1 */ Ns3DebugPrint(0x10,(KERN_DEBUG "COMMAND ")); while (cdbLength > 0) { Ns3DebugPrint(0x10,(KERN_DEBUG "[%x]",*cdb)); SCSI_WRITE(baseAddress, COMMANDDATA, *cdb++); cdbLength--; } Owattayo = 0; /* --- Start Arbitration for Get Bus--- */ dataByte = 0; ((PSET_ARBIT)&dataByte)->ArbitGo = 1; SCSI_WRITE(baseAddress, SETARBIT, dataByte); /* Start Arbitration */ Ns3DebugPrint(0x10,( "-- Start Arbitration -- ")); dataByte = 0; while (!( ((PARBIT_STATUS)&dataByte)->ArbitWin || ((PARBIT_STATUS)&dataByte)->ArbitFail ) ) { dataByte = SCSI_READ(baseAddress, ARBITSTATUS); /* Get bus? */ } if ( ((PARBIT_STATUS)&dataByte)->ArbitFail ) { /* ...I'm looser */ dataByte = 0; ((PSET_ARBIT)&dataByte)->ArbitFlagClear = 1; SCSI_WRITE(baseAddress, SETARBIT, dataByte);/* Arbitration flg Clear*/ DevExt->ScsiState = SC_BUSFREE; srb->result = DID_TIME_OUT <<16; Ns3NotifyCompletion(DevExt, DID_NO_CONNECT); #ifdef USE_IRQ_MASK /* Timer IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 0; /* SCSI IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0; SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData); #endif /* USE_IRQ_MASK */ #ifdef USE_SELECTSAVEFLAG restore_flags(flags); #endif /* USE_SELECTSAVEFLAG */ return(FALSE); } /* Win !*/ udelay(2); /*----- selection phase -----*/ dataByte = (1 << SCSI_INITIATOR_ID) | (1 << (srb->target)); /* set initiator ID + target ID */ SCSI_WRITE(baseAddress, SCSIDATALATCH, dataByte); dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->ScsiSel = 1; ((PSCSI_BUS_CONTROL)&dataByte)->ScsiBSY = 1; dataByte |= AtnByte; SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte); /* put SEL + Busy + ATN*/ udelay(2); /*DELEY ScsiPortStallExecution(1); wait 1.2us*/ ((PSCSI_BUS_CONTROL)&dataByte)->ScsiDataOutEnb = 1; SCSI_WRITE(baseAddress,SCSIBUSCTRL , dataByte); /* enable ID out */ dataByte = 0; ((PSET_ARBIT)&dataByte)->ArbitFlagClear = 1; SCSI_WRITE(baseAddress, SETARBIT, dataByte); /* Arbitration flag Clear*/ dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->ScsiSel = 1; dataByte |= AtnByte; ((PSCSI_BUS_CONTROL)&dataByte)->ScsiDataOutEnb = 1; SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte); /* Busy off*/ DevExt->TimerCount = 250; DevExt->TimerCycle = 1000/51; SCSI_WRITE(baseAddress, TIMERCOUNT, 1000/51); /* 1msec TIMER START*/ do { BusyByte = SCSI_READ(baseAddress, SCSIBUSMON); if ( ((PSCSI_BUS_MONITOR)&BusyByte)->Scsi_BSY ) { /*? (busy)*/ break; } dataByte = SCSI_IRQ_MONITOR(baseAddress); if ( ((PIRQ_STATUS)&dataByte)->TimerIrqStatus ) { SCSI_IRQ_CONTROL(baseAddress, dataByte); DevExt->TimerCount--; SCSI_WRITE(baseAddress, TIMERCOUNT, 1000/51);/* 1msec TIMER START*/ } } while ( DevExt->TimerCount != 0 ); dataByte = SCSI_IRQ_MONITOR(baseAddress) & 0xf0; ((PIRQ_CONTROLP)&dataByte)->TimerIrqClear = 1; /* Clear Timer IRQ*/ SCSI_IRQ_CONTROL(baseAddress, dataByte); DevExt->TimerCount = 0; if ( ! (((PSCSI_BUS_MONITOR)&BusyByte)->Scsi_BSY) ) { /* ----- None... ----- */ SCSI_WRITE(baseAddress, SCSIBUSCTRL, 0); /* SEL Off*/ DevExt->ScsiState = SC_BUSFREE; Ns3NotifyCompletion(DevExt, DID_NO_CONNECT); #ifdef USE_IRQ_MASK /* Timer IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 0; /* SCSI IRQ Enable*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0; SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData); #endif/* USE_IRQ_MASK */ #ifdef USE_SELECTSAVEFLAG restore_flags(flags); #endif /* USE_SELECTSAVEFLAG */ return(FALSE); } /* //--- Success Selection --- */ dataByte = 0; dataByte |= AtnByte; SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte); /* SEL off*/ DevExt->TimerCount = 0; SCSI_WRITE(baseAddress, TIMERCOUNT, 0); /* Timer stop9 */ SCSI_WRITE(baseAddress, TIMERCOUNT, 0); /* Timer stop needs 2times */ /*AutoDirec / ACK Enable (Not same time in SEL off ...) */ ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; ((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1; SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte); targetState = &DevExt->TargetState[srb->target]; /* set sync parameter*/ dataByte = 0; ((PSYNC_REG)&dataByte)->SyncPeriod = targetState->SynchronousPeriod; ((PSYNC_REG)&dataByte)->SyncOffset = targetState->SynchronousOffset; SCSI_WRITE(baseAddress, SYNCREG,dataByte); SCSI_WRITE(baseAddress, ACKWIDTH, targetState->AckWidth); #ifdef MUST_USEIO8 /* 0630 */ dataByte = DevExt->TransferMode; ((PTRANSFER_MODE)&dataByte)->AdrData24 = 0; ((PTRANSFER_MODE)&dataByte)->MemMap8 = 0; ((PTRANSFER_MODE)&dataByte)->MemMap16_32 = 0; ((PTRANSFER_MODE)&dataByte)->AdrData32 = 0; ((PTRANSFER_MODE)&dataByte)->IO8 = 1; ((PTRANSFER_MODE)&dataByte)->IO16_32 = 0; #endif Ns3SetTransferMode( DevExt ); DevExt->ScsiState = SC_SELECT; /* Adapter ready for next request. */ DevExt->IntWait = TRUE; #ifdef USE_SELECTSAVEFLAG restore_flags(flags); #endif /* USE_SELECTSAVEFLAG */ return(TRUE); } /* end Ns3Select()*/ static void ninja3_interrupt( void *data ) { Scsi_Cmnd *cmd; #ifdef USE_IRQ_HANDLE_PRESENT IRQ_STATUS IrqStatus; #endif pnin_softc DevExt = &nin_data[0]; cmd = DevExt->ActiveUnit->ActiveCommand; /* 0629 ?*/ if( !cmd ) { return; } if( mabort ) { if( mabort == 1 ) { cmd->result = DID_ABORT << 16; } else { cmd->result = DID_RESET << 16; } mpcmd = NULL; cmd->scsi_done(cmd); DevExt->ActiveUnit->ActiveCommand = NULL; return; } ninintr( 0 ); mpcmd = NULL; #ifndef USE_IRQ_HANDLE_PRESENT if(!Owattayo) { queue_task(&mps_tq,&tq_scheduler); } #endif return; } boolean Ns3Initialize(int unit) { pnin_softc DevExt = &(nin_data[unit]); /* PSPECIFIC_TARGET_EXTENSION targetState;*/ u_long i; u_long FifoMax = 0x10000; u_char dataByte; TRANSFER_MODE xferMode; int baseAddress = mbase; /*DevExt->BaseAddress;*/ u_char DefaultXfer = 0; DevExt->unit = unit; DevExt->BaseAddress = mbase; #ifndef USE_DISCONECT DevExt->AdapterOption = OPT_NON_DISCONECT; #endif /* USE_DISCONECT */ *((u_char *)&xferMode) = 0; #ifdef 0/* 0629*/ xferMode.MemMap8 = 1; xferMode.MemMap16_32 = 1; xferMode.AdrData24 = 1; xferMode.IO16_32 = 1; #endif xferMode.MemMap8 = 0; xferMode.MemMap16_32 = 0; xferMode.AdrData24 = 0; xferMode.IO16_32 = 0; xferMode.IO8 = 1; FifoMax = 0x10000; DevExt->SSEntry = 0; xferMode.MemMap16_32 = 0; xferMode.AdrData24 = 0; xferMode.MemMap8 = 0; DevExt->TransferMode= *(u_char *)&xferMode; /* Set default-trans-mode*/ (*(u_char *)&xferMode) = 0; xferMode.FifoTest_Braind = 0; xferMode.TransferGo = 0; /* magic word. Don't delete. */ printk(" "); /* TransferModeSet & TEST MODE OFF */ SCSI_WRITE(baseAddress, TRANSFERMODE, *(u_char *)&xferMode); #ifdef USE_32BITTRANSFER DevExt->pXferRead = pio32_datain; DevExt->pXferWrite = pio32_dataout; #else DevExt->pXferRead = pio8_datain; DevExt->pXferWrite = pio8_dataout; #endif /* USE_32BITTRANSFER */ /* FindAdapter*/ /* if hang-up any Phase and reset、then Busfree Interrupt*/ SCSI_WRITE(baseAddress, SCSIIRQMODE, 0); /* SCSI IRQ ALL DISABLE*/ SCSI_IRQ_CONTROL(baseAddress, 0xff); /* IRQ all Mssk & clear */ #ifdef ULTRA SCSI_WRITE(baseAddress, CLOCKDIV , 2); /* 40MHz */ #else SCSI_WRITE(baseAddress, CLOCKDIV , 1); /* 20MHz */ #endif dataByte = 0; ((PSCSI_IRQ_MODE)&dataByte)->ScsiResetIrqEi = 1; ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0; /* Disable FIFO IRQ*/ ((PSCSI_IRQ_MODE)&dataByte)->ReselectIrqEi = 1; ((PSCSI_IRQ_MODE)&dataByte)->ScsiPhaseChangeEi = 1; SCSI_WRITE(baseAddress, SCSIIRQMODE, dataByte); SCSI_WRITE(baseAddress, PARITYCTRL , 0); /* Parity Disable*/ SCSI_WRITE(baseAddress, POINTERCLR , 0xf); /* All Pointer Clear*/ dataByte = 0; ((PIF_SELECT)&dataByte)->RegSelect = 1; SCSI_IF_SELECT(baseAddress, dataByte); /* FIFO Status Read set*/ /**/ /* Reset Ns3 and SCSI bus.*/ /**/ DevExt->InterruptPending = FALSE; DevExt->DmaPending = FALSE; /*Terminator Off !*/ SCSI_WRITE(baseAddress, TERMPWRCTRL, 0); /* Terminator Off !*/ dataByte = SCSI_READ(baseAddress, OTHERCONTROL); if ( ! ((POTHER_CONTROL)&dataByte)->TermPwrSence ) /* Term Power ?;*/ SCSI_WRITE(baseAddress, TERMPWRCTRL, 1); /* Terminator ON !*/ /**/ /*--- SCSI BUS RESET ---*/ /**/ Ns3ResetScsiBus( DevExt ); /**/ /*--- Cable Check ---*/ /**/ DevExt->ScsiCable = TRUE; if ( (SCSI_READ(baseAddress,SCSIDATAIN)) || (SCSI_READ(baseAddress,SCSIBUSMON)) ) { DevExt->ScsiCable = FALSE; SCSI_WRITE(baseAddress, TERMPWRCTRL, 0); /* Terminator Off !*/ } *(u_char *)&xferMode = DevExt->TransferMode; /**/ /* Can TransferMode Clear*/ /**/ for ( i = 0; i < 6; i++ ) { DevExt->CanTransMode[i] = DefaultOk[i]; } /**/ /* At first, Test for TransferMode in default */ /**/ DefaultXfer = Ns3FifoTest( unit,&DevExt->CanTransMode[0]); xferMode =(*(PTRANSFER_MODE)&DefaultXfer); /* if ( DevExt->AdapterOption & OPT_TUNEUP_DI ) Disable Transfer tune? goto Set_transfer_mode; */ /*Set_transfer_mode:*/ DevExt->TransferMode= *(u_char *)&xferMode; /* TransferModeSet & TEST MODE OFF */ SCSI_WRITE(baseAddress, TRANSFERMODE, *(u_char *)&xferMode); if ( xferMode.IO16_32 ) { DevExt->pXferRead = pio32_datain; DevExt->pXferWrite = pio32_dataout; } else if ( xferMode.IO8 ) { DevExt->pXferRead = pio8_datain; DevExt->pXferWrite = pio8_dataout; } SCSI_WRITE(baseAddress, CLOCKDIV , 2); /* 20MHz *[v1.03]*/ return TRUE; } /* end Ns3Initialize()*/ /* //----------------------------------------------------------------------- // Routine Name: // Ns3NotifyCompletion // // Routine Description: // // This routine will perform any clean up operations for the Srb // and notify the ScsiPort driver of completion. // //----------------------------------------------------------------------- */ void Ns3NotifyCompletion( IN pnin_softc DevExt, IN boolean host_byte ) { Scsi_Cmnd *srb = DevExt->ActiveUnit->ActiveCommand; Ns3DebugPrint(0x10,(KERN_DEBUG "scsi_done[%x]\n",srb->cmnd[0])); ScsiPortFreeLogicalUnit( srb->target, srb->lun); Owattayo = 1; /* srb->flags |= ITSDONE; */ srb->result = host_byte << 16; srb->result = (host_byte << 16) | ((srb->SCp.Message & 0xff) << 8); srb->scsi_done(srb); #ifdef USE_SLEEP_WAKE wake_up_interruptible(&read_wait); #endif /* USE_SLEEP_WAKE */ } /* end Ns3NotifyCompletion()*/ /* //---------------------------------------------------------------------------- // Set transger mode & ruotine //---------------------------------------------------------------------------- */ void Ns3SetTransferMode( IN pnin_softc DevExt ) { PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit; unsigned char dataByte; LuExtension->pXferRead = DevExt->pXferRead; LuExtension->pXferWrite = DevExt->pXferWrite; /* FIFOTest & Option Set TransferMode*/ dataByte = DevExt->TransferMode; ((PTRANSFER_MODE)&dataByte)->TransferGo = 1; ((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 1; /* Set transfer mode*/ SCSI_WRITE(DevExt->BaseAddress, TRANSFERMODE, dataByte); } /* //----------------------------------------------------------------------- // read FIFO // //----------------------------------------------------------------------- */ unsigned long read_ack_count ( IN pnin_softc DevExt ) { int baseAddress = DevExt->BaseAddress; unsigned char dataByte; unsigned char CountL,CountM, CountH; unsigned long Count, Counter; dataByte = 0; ((PPOINTER_CLEAR)&dataByte)->PointerClear = 1; SCSI_WRITE(baseAddress, POINTERCLR, dataByte); /* ACK counter read set*/ CountL = inb(baseAddress+DATAREG); CountM = inb(baseAddress+DATAREG); CountH = inb(baseAddress+DATAREG); /* ScsiPortReadPortUchar( (unsigned char *)&((baseAddress)->DATAREG) );*/ Counter = (unsigned long)( CountH*65536 + CountM*256 + CountL); /* Check Card */ if ( Counter == 0xffffff ) return (0); /* Counter value at Disconnect */ Ns3DebugPrint(0x008, ("read_ack_count[%x]\n",Counter)); Count = Counter + DevExt->ActiveUnit->AckCounter; Count -= DevExt->ActiveUnit->TransferedLength; return ( Count ); } /************************************************************/ /* //----------------------------------------------------------------------- // TransferRoutine // //----------------------------------------------------------------------- // */ /* --- PIO 32bit DataInTransfer ---- */ void pio32_datain (int BaseAddress , char* Buffer, u_long Length ) { /* u_int port = BaseAddress+WFIFODATA;*/ if ( Length & 0x3 ) { Ns3DebugPrint(0x01,(KERN_DEBUG "SCSI_READ_FIFOW [%x] (%x)byte", Buffer , Length)); SCSI_READ_FIFOW(BaseAddress, (char *)Buffer , Length); } else { SCSI_READ_FIFOD(BaseAddress, Buffer , Length); } } /* --- PIO 32bit DataOutTransfer ---- */ void pio32_dataout (int BaseAddress , char* Buffer, u_long Length ) { if ( Length & 0x3 ) { SCSI_WRITE_FIFOW(BaseAddress, (char *)Buffer , Length); } else { SCSI_WRITE_FIFOD(BaseAddress, (char *)Buffer , Length); } } /* --- PIO 8bit DataInTransfer ---- */ void pio8_datain (int BaseAddress , char* Buffer, u_long Length ) { SCSI_READ_FIFO(BaseAddress, Buffer , Length); } /* --- PIO 8bit DataOutTransfer ---- */ void pio8_dataout (int BaseAddress , char* Buffer, u_long Length ) { SCSI_WRITE_FIFO(BaseAddress, Buffer , Length); } void Ns3BurstRead( IN pnin_softc DevExt ) { u_long Length; IRQ_STATUS IrqStatus; FIFO_STATUS FifoStatus; int baseAddress = DevExt->BaseAddress; PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit; while( DevExt->CurDataLength > 0 ) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); /* 0629 ORESAMA*/ if ( IrqStatus.ScsiIrqStatus ) { break; /** PhaseChange ? ***/ } /* 0629 ORESAMA*/ *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty ) { Length = DevExt->CurDataLength; /* change maxmum transfer size*/ if ( Length > READ_XFER_CNT) Length = READ_XFER_CNT; /* Call for TransferRoutine */ (*LuExtension->pXferRead)( baseAddress, DevExt->CurDataPointer, Length ); DevExt->CurDataPointer += Length; DevExt->CurDataLength -= Length; DevExt->ActiveUnit->TransferedLength += Length; } } /* See now,but PhaseChange */ *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); /* Stop PhaseChange interrupt */ if ( IrqStatus.ScsiIrqStatus ) { /* PhaseChange ?*/ if ( DevExt->CurDataLength > 0) { Length = read_ack_count(DevExt); if (!(Length & 0x80000000)) { /* +[v0.32]*/ (*LuExtension->pXferRead)( baseAddress, DevExt->CurDataPointer, Length ); } DevExt->CurDataPointer += Length; DevExt->CurDataLength -= Length; DevExt->ActiveUnit->TransferedLength += Length; } } DevExt->ScsiState = SC_DATA; } /* //----------------------------------------------------------------------- // blind write // //----------------------------------------------------------------------- */ void Ns3BurstWrite( IN pnin_softc DevExt ) { u_long Length; IRQ_STATUS IrqStatus; FIFO_STATUS FifoStatus; int baseAddress = DevExt->BaseAddress; PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit; while( DevExt->CurDataLength > 0 ) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( IrqStatus.ScsiIrqStatus ) break; /* PhaseChange ?*/ *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty) { Length = DevExt->CurDataLength; /* change maximum transfer number*/ if ( Length > WRITE_BURST_CNT) Length = WRITE_BURST_CNT; /* Call for TransferRoutine */ (*LuExtension->pXferWrite)( baseAddress, DevExt->CurDataPointer, Length ); DevExt->CurDataPointer += Length; DevExt->CurDataLength -= Length; DevExt->ActiveUnit->TransferedLength += Length ; } } /* See now,but PhaseChange after sending */ *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); /* remain data inFIFO at PhaseChange */ if ( IrqStatus.ScsiIrqStatus ) { /* PhaseChange ?*/ if ( (Length = read_ack_count(DevExt)) ) { /* Length is Minus*/ DevExt->CurDataPointer += Length; DevExt->CurDataLength -= Length; /* pointerwomodosu*/ DevExt->ActiveUnit->TransferedLength += Length ; } } DevExt->ScsiState = SC_DATA; } /* //----------------------------------------------------------------------- // spot read // //----------------------------------------------------------------------- */ void Ns3SpotRead ( IN pnin_softc DevExt ) { u_char dataByte; int baseAddress = DevExt->BaseAddress; IRQ_STATUS IrqStatus; FIFO_STATUS FifoStatus; u_long FifoCount; long LoopCount = 0; u_char ScsiPhase; long i; PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit; ScsiPhase = SCSI_READ(baseAddress, SCSIBUSMON) & 0x7; if ( ScsiPhase == BP_DATA_IN ) { if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1; /* FIFO IRQ Enable*/ SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); /* Release FIFO IRQ MASK */ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; } while (LoopCount == 0) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( IrqStatus.ScsiIrqStatus ) break; /* PhaseChange ?*/ *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty ) { dataByte = 0xf0; ((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1; SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/ /* Read FIFO */ FifoCount = read_ack_count( DevExt ) & 0xfffffe; /* Call for TransferRoutine */ (*LuExtension->pXferRead)( baseAddress, DevExt->CurDataPointer, FifoCount ); DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer += FifoCount; DevExt->ActiveUnit->TransferedLength += FifoCount ; LoopCount++; DevExt->IntWait = FALSE; for ( i = 0; i< INT_POLL_IRQ ; i++) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( IrqStatus.ScsiIrqStatus ) break; /* PhaseChange ?*/ *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty ) { /* FIFO FULL */ LoopCount = 0; /* One moer*/ break; } udelay(2);/*ScsiPortStallExecution(2);*/ } } } } else { /* other phase*/ FifoCount = read_ack_count( DevExt ); /* Get FIFOremain*/ (*LuExtension->pXferRead)( baseAddress, DevExt->CurDataPointer, FifoCount ); DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer += FifoCount; DevExt->ActiveUnit->TransferedLength += FifoCount ; dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* Disable FIFO IRQ */ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); #ifdef USE_IRQ_MASK /* FIFO IRQ MASK*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; #endif /* USE_IRQ_MASK */ DevExt->IntWait = TRUE; return; } /* Stoped in PhaseChange */ if ( IrqStatus.ScsiIrqStatus && ( FifoCount = read_ack_count(DevExt))) { (*LuExtension->pXferRead)( baseAddress, DevExt->CurDataPointer, FifoCount ); DevExt->CurDataPointer += FifoCount; DevExt->CurDataLength -= FifoCount; DevExt->ActiveUnit->TransferedLength += FifoCount; dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* Disable FIFO IRQ */ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); #ifdef USE_IRQ_MASK /* FIFO IRQ MASK*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; DevExt->IntWait = TRUE; #endif /* USE_IRQ_MASK */ } DevExt->ScsiState = SC_DATA; /* Wait for next FifoFull */ } /* //----------------------------------------------------------------------- // //----------------------------------------------------------------------- */ void Ns3SpotWrite ( IN pnin_softc DevExt ) { u_char dataByte; int baseAddress = DevExt->BaseAddress; IRQ_STATUS IrqStatus; FIFO_STATUS FifoStatus; u_long FifoCount; long LoopCount = 0; long i; PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit; if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* FIFO IRQ Enable*/ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); /* Release FIFO IRQ MASK */ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; } while (LoopCount == 0) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( IrqStatus.ScsiIrqStatus ) { break; /* PhaseChange ?*/ } *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty) { dataByte = 0xf0; ((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1; SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/ FifoCount = WRITE_SPOT_CNT; if ( DevExt->CurDataLength < WRITE_SPOT_CNT ){ FifoCount = DevExt->CurDataLength; } /* Call for TransferRoutine */ (*LuExtension->pXferWrite)( baseAddress, DevExt->CurDataPointer, FifoCount ); DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer += FifoCount;; DevExt->ActiveUnit->TransferedLength += FifoCount ; if ( DevExt->CurDataLength == 0 ) { DevExt->IntWait = TRUE; break; } LoopCount++; DevExt->IntWait = FALSE; for ( i = 0; i< INT_POLL_IRQ ; i++) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if ( IrqStatus.ScsiIrqStatus ) { break; /* PhaseChange ?*/ } *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty ) { /* if FIFO Empty*/ LoopCount = 0; /* Once more*/ break; } udelay(2); /* ScsiPortStallExecution(2); */ } } } if ( IrqStatus.ScsiIrqStatus ) { /* PhaseChange ?*/ DevExt->IntWait = TRUE; } DevExt->ScsiState = SC_DATA; /* Next FifoEmpty Wait*/ } /* //----------------------------------------------------------------------- // Slow Read // //----------------------------------------------------------------------- */ void Ns3SlowRead ( IN pnin_softc DevExt ) { char* Buffer = DevExt->CurDataPointer; u_char dataByte; int baseAddress = DevExt->BaseAddress; IRQ_STATUS IrqStatus; FIFO_STATUS FifoStatus; u_long FifoCount; long LoopCount = 0; u_char ScsiPhase; dataByte = 0; ((PTRANSFER_MODE)&dataByte)->TransferGo = 1; ((PTRANSFER_MODE)&dataByte)->IO8 = 1; ((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0; SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte); /* Set Transfer Mode*/ ScsiPhase = SCSI_READ(baseAddress, SCSIBUSMON) & 0x7; if ( ScsiPhase == BP_DATA_IN ) { if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* FIFO IRQ Enable*/ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); /* Release FIFO IRQ MASK*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; } while (LoopCount == 0) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty ) { /* FIFO FULL?*/ dataByte = 0xf0; ((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1; SCSI_IRQ_CONTROL(baseAddress, dataByte); /* Clear IRQ*/ } if ( FifoStatus.FifoFullEmpty || IrqStatus.ScsiIrqStatus) { FifoCount = read_ack_count( DevExt );/* Get FIFO remain*/ SCSI_READ_FIFO( baseAddress, Buffer, FifoCount ); Buffer += FifoCount; DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer = Buffer; DevExt->ActiveUnit->TransferedLength += FifoCount ; LoopCount++; } } } else { /* otheer Phase*/ FifoCount = read_ack_count( DevExt ); /* read FIFO remain*/ SCSI_READ_FIFO( baseAddress, Buffer, FifoCount ); Buffer += FifoCount; DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer = Buffer; DevExt->ActiveUnit->TransferedLength += FifoCount ; return; } DevExt->ScsiState = SC_DATA; /* Wait for next FifoFull */ } /* //----------------------------------------------------------------------- // //----------------------------------------------------------------------- */ void Ns3SlowWrite ( IN pnin_softc DevExt ) { char* Buffer = DevExt->CurDataPointer; u_char dataByte; int baseAddress = DevExt->BaseAddress; /* IRQ_STATUS IrqStatus;*/ FIFO_STATUS FifoStatus; u_long FifoCount; dataByte = 0; ((PTRANSFER_MODE)&dataByte)->TransferGo = 1; ((PTRANSFER_MODE)&dataByte)->IO8 = 1; ((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0; SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte); /* TransferModeSet*/ if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* FIFO IRQ Enable*/ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); /* Enable FIFO IRQ MAS K*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; } /* *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);*/ *((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress); if ( FifoStatus.FifoFullEmpty) { dataByte = 0xf0; ((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1; SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/ FifoCount = 32; if ( DevExt->CurDataLength < 32 ) FifoCount = DevExt->CurDataLength; SCSI_WRITE_FIFO ( baseAddress, Buffer, FifoCount ); Buffer += FifoCount; DevExt->CurDataLength -= FifoCount ; DevExt->CurDataPointer = Buffer; DevExt->ActiveUnit->TransferedLength += FifoCount ; } DevExt->ScsiState = SC_DATA; /* Wait for Next FifoEmpty*/ } /* //----------------------------------------------------------------------- // Routine Name: // // Ns3RunPhase // // Routine Description: // // This routine runs through the bus phases until some type of completion // indication is received. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // None. // //----------------------------------------------------------------------- */ void Ns3RunPhase( IN pnin_softc DevExt, IN IRQ_PHASE_SENSE IrqPhase ) { int baseAddress = DevExt->BaseAddress; u_char dataByte; u_long Count; PSPECIFIC_TARGET_EXTENSION targetState; /* slow transfer proc*/ if ( IrqPhase.PhaseChgIrq && ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask == 0 ) { /* still ?*/ if ( (Count = read_ack_count(DevExt)) ) { if ( DevExt->ScsiPrePhase == BP_DATA_IN) {/* prvious phase*/ Ns3DataInPhase(DevExt); }else { DevExt->CurDataLength -= Count; /* back pointer*/ DevExt->CurDataPointer += Count; /* Number of transfer-length */ DevExt->ActiveUnit->TransferedLength += Count; } } dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE); /* FIFO IRQ desable*/ ((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0; SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte); #ifdef USE_IRQ_MASK /* FIFO IRQ MASK*/ ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; #endif /* USE_IRQ_MASK */ } /* //--- BUS FREE ( DISCONNETCT ) ? ---- */ /*interrput in BusFree*/ if ( IrqPhase.LatchBusFree ) { /* trans-mode is FIFOtest/option*/ dataByte = DevExt->TransferMode; ((PTRANSFER_MODE)&dataByte)->TransferGo = 0; ((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0; /* TransferModeSet*/ SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte); /* Save AckCounter*/ DevExt->ActiveUnit->AckCounter = DevExt->ActiveUnit->TransferedLength; if ( DevExt->ScsiState == SC_COMPLETE ) { Ns3NotifyCompletion(DevExt, DID_OK); DevExt->ScsiState = SC_BUSFREE; DevExt->IntWait = FALSE; return; } else if (DevExt->ScsiState == SC_DISCONNECT ) { Ns3DebugPrint(0x008, (KERN_DEBUG "LatchBusFree:ScsiState == SC_DISCONNECT \n")); Ns3DebugPrint(0x008, ("LatchBusFree:ScsiState == SC_DISCONNECT \n")); DevExt->ScsiState = SC_BUSFREE; return; } Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: Unexpected bus disconnect[%x].\n", DevExt->ScsiState)); targetState = &DevExt->TargetState[DevExt ->TargetId]; if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) { targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT; targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE; } DevExt->ScsiState = SC_BUSFREE; /* ScsiPortLogError(DevExt,SP_UNEXPECTED_DISCONNECT,10); */ Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase:SC_BUSFREE-bye!\n")); return; } (*(u_char *)&IrqPhase) &= 0x7; DevExt->ScsiPrePhase = (*(u_char *)&IrqPhase); switch (DevExt->ScsiPrePhase) { case BP_COMMAND: /* Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_COMMAND \n"));*/ Ns3SendCDB(DevExt); /*Start commans phase*/ break; case BP_DATA_IN: Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_DATA_IN \n")); Ns3DataInPhase(DevExt); /* Start data phase*/ break; case BP_DATA_OUT: Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_DATA_OUT \n")); Ns3DataOutPhase(DevExt); /* Start data phase*/ break; case BP_STATUS: Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_STATUS ")); Ns3Status(DevExt); break; case BP_MESSAGE_IN: Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_MESSAGE_IN ")); Ns3MessageIn(DevExt); break; case BP_MESSAGE_OUT: Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_MESSAGE_OUT \n")); Ns3MessageOut(DevExt); break; default: DevExt->ScsiState = SC_COMPLETE; break; } #ifdef RUNPHASE_AUTODIRECTION dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); #endif /* RUNPHASE_AUTODIRECTION 0704 */ } /* end Ns3RunPhase()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3DataInPhase // // Routine Description: // // This routine sets the DmaPending flag in the device extension, // calls the OS-specific driver to set up the system DMA chip, // and returns. Control is received again in DmaStarted when the DMA // setup is complete. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // TRUE if DMA started // FALSE if missed request // //----------------------------------------------------------------------- */ void Ns3DataInPhase( IN pnin_softc DevExt ) { u_char targetId = DevExt->TargetId; u_char devType; /* u_long TransferLength = DevExt->CurDataLength;*/ DevExt->InterruptPending = FALSE; /* flag clear*/ DevExt->DmaPending = TRUE; devType = DevExt->DeviceType[targetId]; Ns3DebugPrint(0x10, ("Ns3DataInPhase in ")); if (( DevExt->ActiveUnit-> /* ActiveCommand->datalen < 0x100 0625*/ ActiveCommand->request_bufflen < 0x100 ) || /* || (TransferLength & 0x3) ) { *[v1.02]*/ ( DevExt->ActiveUnit-> ActiveCommand->request_bufflen & 3 ) ) { Ns3SlowRead ( DevExt ); /* Not divaid less than 256, 4dewarikrenai? */ return; } #ifdef USE_SPOTREAD_ONLY Ns3SpotRead ( DevExt ); #else switch ( devType ) { case 0: case 5: Ns3BurstRead( DevExt ); break; default: Ns3SpotRead ( DevExt ); break; } #endif /* USE_SPOTREAD_ONLY */ #ifdef USE_SLEEP_WAKE interruptible_sleep_on(&read_wait); #endif /* USE_SLEEP_WAKE */ /* ------ ORESAMA ------ if(!DevExt->CurDataLength) { Ns3NotifyCompletion(DevExt, FALSE); DevExt->ScsiState = SC_COMPLETE; } ------ ORESAMA ------ */ } /* end Ns3DataInPhase()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3DataOutPhase // // Routine Description: // // This routine sets the DmaPending flag in the device extension, // calls the OS-specific driver to set up the system DMA chip, // and returns. Control is received again in DmaStarted when the DMA // setup is complete. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // TRUE if DMA started // FALSE if missed request // //----------------------------------------------------------------------- */ void Ns3DataOutPhase( IN pnin_softc DevExt ) { u_char targetId = DevExt->TargetId; u_char devType; /* u_long TransferLength = DevExt->CurDataLength;*/ u_char dataByte; DevExt->InterruptPending = FALSE; /* flag clear*/ DevExt->DmaPending = TRUE; devType = DevExt->DeviceType[targetId]; if ( (DevExt->ActiveUnit-> ActiveCommand->request_bufflen < 0x100) || (DevExt->ActiveUnit-> ActiveCommand->request_bufflen & 3) ) { Ns3SlowWrite ( DevExt ); /* Smaller than 256 or x/4 != 0 ? */ return; } dataByte = DevExt->TransferMode; /* Set TransferMode in FIFOTest / Option */ /* munya.. */ Ns3SpotWrite ( DevExt ); } /* end Ns3DataOutPhase()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3SendCDB // // Routine Description: // // Send the SCSI Command Descriptor Block (CDB) to the indicated target/lun. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // None // //----------------------------------------------------------------------- */ void Ns3SendCDB( IN pnin_softc DevExt ) { int baseAddress = DevExt->BaseAddress; u_char dataByte; #ifdef DBG_PRINT Scsi_Cmnd *cmd = DevExt->ActiveUnit->ActiveCommand; Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3SendCDB enter(%x)!\n",cmd->target)); #endif dataByte = SCSI_READ(baseAddress, SCSIBUSMON); if ( ((PSCSI_BUS_MONITOR)&dataByte)->Scsi_ATN ) { /* Still ATN ?*/ /* SCSI-1 Device */ dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; ((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1; SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte); /* ATN off*/ } /* Clear transfer counter*/ dataByte = 0; ((PPOINTER_CLEAR)&dataByte)->PointerClear = 1; ((PPOINTER_CLEAR)&dataByte)->AckCounterClear = 1; ((PPOINTER_CLEAR)&dataByte)->ReqCounterClear = 1; ((PPOINTER_CLEAR)&dataByte)->HostCounterClear = 1; SCSI_WRITE(baseAddress, POINTERCLR, dataByte); DevExt->ActiveUnit->AckCounter = 0; DevExt->ActiveUnit->HostCounter = 0; /* send CDB*/ dataByte = 0; ((PCOMMAND_CONTROL)&dataByte)->AutoCommandGo = 1; ((PCOMMAND_CONTROL)&dataByte)->ClrCommandPointer = 1; SCSI_WRITE(baseAddress, COMMANDCTRL, dataByte); DevExt->ScsiState = SC_UNDETERMINED; /* // Set up the running data pointer info for a possible data transfer. */ DevExt->CurDataPointer = DevExt->ActiveUnit->SavedDataPointer; DevExt->CurDataLength = DevExt->ActiveUnit->SavedDataLength; DevExt->ActiveUnit->TransferedLength = 0; /* Enable Interrupt */ DevExt->InterruptPending = TRUE; } /* end Ns3SendCDB()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3MessageOut // // Routine Description: // // This routine will sent the message to the target. // //----------------------------------------------------------------------- */ void Ns3MessageOut( IN pnin_softc DevExt ) { int baseAddress = DevExt->BaseAddress; u_char dataByte; u_char * msg = &DevExt->MessageBuffer[0]; IRQ_STATUS IrqStatus; /* MessageOut,NoOperation*/ if ( DevExt->MessageCount == 0 ) { DevExt->MessageBuffer[0] = MSG_NOOP; DevExt->MessageCount = 1; } do { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); if (IrqStatus.ScsiIrqStatus) { break; } dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK; if ( dataByte == BM_MESSAGE_OUT ) { if ( DevExt->MessageCount == 1) { /* last byte ?*/ dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; ((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1; /* ATN Off !*/ SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); } /* message output*/ SCSI_WRITE(baseAddress ,SCSIDATAWITHACK, *msg); Ns3WaitForAckOff(DevExt); msg++; DevExt->MessageCount--; } } while ( DevExt->MessageCount != 0 ); /* phase change. Off ATN */ if ( IrqStatus.ScsiIrqStatus && DevExt->MessageCount != 0) { dataByte = 0; ((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1; ((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ATN Off !*/ } DevExt->ScsiState = SC_UNDETERMINED; } /* end Ns3MessageOut()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3MessageIn // // Routine Description: // // This routine will receive the message from the target. // //----------------------------------------------------------------------- */ void Ns3MessageIn( IN pnin_softc DevExt ) { PSPECIFIC_LU_EXTENSION luExtension; Scsi_Cmnd * srb; int baseAddress = DevExt->BaseAddress; u_char * msg = &DevExt->MessageBuffer[0]; u_char dataByte; IRQ_STATUS IrqStatus; u_long MessageCount = 0; boolean NegAck = TRUE; PSPECIFIC_TARGET_EXTENSION targetState; DevExt->MessageCount = 0; Ns3DebugPrint(0x008, ("Ns3MessageIn in ")); luExtension = DevExt->ActiveUnit; if ( luExtension ) { /* reselection = NULL*/ srb = luExtension->ActiveCommand; targetState = &DevExt->TargetState[srb ->target]; } else { return; } /* // --- message first byte // read Ninja */ dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK; /* message in phase? is &req?*/ if ( dataByte == BM_MESSAGE_IN ) { /* read msg byte*/ *msg = SCSI_READ(baseAddress, SCSIDATAIN); srb->SCp.Message = *msg; dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 1; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK On !*/ /* if return value is FALSE? */ Ns3WaitForReqOff(DevExt); /* REQ off ?*/ /* //--- Identify Message ? ---- */ if ( *msg & MSG_IDENTIFYFLAG ) {/* 0x80 = MSG_IDENTIFYFLAG ? */ DevExt->TargetLun = *msg & 0xf; /* now reselecting?*/ if ( DevExt->ScsiState == SC_RESELECT ) { Ns3DebugPrint(0x10,(KERN_DEBUG "ScsiState == SC_RESELECT \n")); Ns3ProcessReselection(DevExt); } } else { DevExt->ScsiState = SC_UNDETERMINED; switch ( *msg ) { case MSG_CMDCOMPLETE : DevExt->ScsiState = SC_COMPLETE; break; case MSG_DISCONNECT : Ns3DebugPrint(0x008, ("MSG_DISCONNECT!!\n")); srb->device->disconnect = 1; DevExt->ScsiState = SC_DISCONNECT; /* 0722 */ dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK off !*/ return; /* 0722 */ break; case MSG_SAVEDATAPOINTER : Ns3DebugPrint(0x008, (KERN_DEBUG "MSG_SAVEDATAPOINTER\n")); Ns3DebugPrint(0x008, ("MSG_SAVEDATAPOINTER\n")); MessageCount = 1; /* Wait DISCONNECT msg*/ DevExt->ScsiState = SC_DISCONNECT; luExtension->SavedDataPointer = DevExt->CurDataPointer; luExtension->SavedDataLength = DevExt->CurDataLength; break; case MSG_RESTOREPOINTERS: Ns3DebugPrint(0x008, ("MSG_RESTOREPOINTERS\n")); DevExt->CurDataPointer = luExtension->SavedDataPointer; DevExt->CurDataLength = luExtension->SavedDataLength; break; case MSG_EXTENDED : MessageCount = 6; /* max-len ext-msg*/ if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) MessageCount = 4; NegAck = FALSE; /* Not NEG ACK at last byte*/ break; case MSG_MESSAGE_REJECT: if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) { targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT; targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE; } break; } } dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK Off !*/ msg++; DevExt->MessageCount ++; } /**/ /* --- get next-message*/ *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); while ( !(IrqStatus.ScsiIrqStatus)) { /* still phase-chg*/ dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK; /* no next-msg & control-line not message-in*/ /*-[v0.50] for OLY MO*/ /* if ((MessageCount == 0) && ((dataByte & 0x7) != BP_MESSAGE_IN) )*/ /* break;*/ /* Is mgs-in phase & req ?*/ if ( dataByte == BM_MESSAGE_IN ) { *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); /*if PhaseChange here,maybe Reselection Message*/ if ( IrqStatus.ScsiIrqStatus ) break; *msg = SCSI_READ(baseAddress, SCSIDATAIN);/* read msg-byte */ if ( *msg == MSG_DISCONNECT ) { Ns3DebugPrint(0x008, ("MsgIn:msg == MSG_DISCONNECT\n")); srb->device->disconnect = 1; DevExt->ScsiState = SC_DISCONNECT; } dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 1; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK On !*/ /* if return value is FALSE? */ if ( !Ns3WaitForReqOff(DevExt) ) { /* REQ Off ?*/ Ns3NotifyCompletion(DevExt, DID_NO_CONNECT); } if ( ( MessageCount != 1) || ( MessageCount == 1 && NegAck )) { dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);/* ACK Off !*/ } msg++; DevExt->MessageCount ++; if ( MessageCount != 0 ) MessageCount--; /* if Neg ACK at last Byte Mod, finish*/ if ( MessageCount == 0 && !NegAck ) break; } *((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress); } /* while ( !(IrqStatus.ScsiIrqStatus)); wait for PhaseChange */ if (DevExt->MessageBuffer[0] == MSG_EXT_SDTR ) { dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; /* ACK Off !*/ if (Ns3MessageDecode( DevExt )) /* Is Message after Decode*/ ((PSCSI_BUS_CONTROL)&dataByte)->ScsiATN = 1; /* ATN On !*/ SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); } } /* end Ns3MessageIn()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3Status // // Routine Description: // // This routine will obtain the status from the target. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // None // //----------------------------------------------------------------------- */ void Ns3Status( IN pnin_softc DevExt ) { u_char status; /* u_char srbStatus;*/ u_char dataByte; Scsi_Cmnd *srb ; /*= DevExt->ActiveUnit->ActiveCommand;*/ int baseAddress = DevExt->BaseAddress; if(!DevExt->ActiveUnit) { panic("Ns3Status:DevExt->ActiveUnit == NULL[1]"); } srb = DevExt->ActiveUnit->ActiveCommand; dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK; if ( dataByte == BM_STATUS ) { /* Is Status Phase &req ?*/ status = SCSI_READ(baseAddress, SCSIDATAWITHACK);/* read Status byte*/ srb->SCp.Status = status; switch (status) { case SCSI_CONDITION_MET: srb->flags |= WAS_SENSE; case SCSI_OK: case SCSI_INTERM: case SCSI_INTERMEDIATE_COND_MET: if (srb->cmnd[0] == 0x12 && srb->lun == 0) { /* !! */ DevExt->DeviceType[srb->target] = *(u_char *)(srb->request_buffer); if ( DevExt->DeviceType[srb->target] == 6 || /*+[v1.02]*/ DevExt->DeviceType[srb->target] == 3) { PSPECIFIC_TARGET_EXTENSION targetState; targetState = &DevExt-> TargetState[srb->target]; targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE; } } srb->request_bufflen = /*datalen = srb->DataTransferLength = */ DevExt->ActiveUnit->TransferedLength ; /* srbStatus = SRB_STATUS_SUCCESS;*/ break; case SCSI_CHECK: case SCSI_COMMAND_TERMINATED: /* srbStatus = SRB_STATUS_ERROR;*/ break; case SCSI_BUSY: case SCSI_RESERVATION_CONFLICT: case SCSI_QUEUE_FULL: default: /* srbStatus = SRB_STATUS_BUSY;*/ break; } Ns3WaitForAckOff(DevExt); /**/ /* If some error condition already occurred (e.g., parity error), we'll*/ /* let that one take priority.*/ /**/ /* if (srb->SrbStatus == SRB_STATUS_PENDING) srb->SrbStatus = srbStatus; */ } /* if BM_STATUS*/ DevExt->ScsiState = SC_UNDETERMINED; } /* end Ns3Status()*/ /* //----------------------------------------------------------------------- // Routine Name: // Ns3WaitForAckOff // // Routine Description: // Spin checking the status of the Ns3 adapter until it indicates that // the SCSI ACK line is Low // // Return Value: // TRUE - indicates that the SCSI REQUEST line was Negated in time. // FALSE - indicates timeout occurred while waiting for the SCSI REQUEST // line. //----------------------------------------------------------------------- */ boolean Ns3WaitForAckOff( pnin_softc DevExt ) { int baseAddress = DevExt->BaseAddress; u_long spinCount = REQUEST_SPIN_WAIT; u_char dataByte; do { dataByte = SCSI_READ(baseAddress, SCSIBUSMON); if ( !((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_ACK ) {/* ACK Off ?*/ return TRUE; } udelay(2); } while (spinCount--); Ns3NotifyCompletion(DevExt, DID_TIME_OUT); return FALSE; } /* end Ns3WaitForAckOff()*/ /* //----------------------------------------------------------------------- // Routine Name: // // Ns3WaitForReqOff // // Routine Description: // // Spin checking the status of the Ns3 adapter until it indicates that // the SCSI REQUEST line is high. // // Arguments: // // DevExt - Device adapter context pointer. // // Return Value: // // TRUE - indicates that the SCSI REQUEST line was asserted in time. // FALSE - indicates timeout occurred while waiting for the SCSI REQUEST // line. //----------------------------------------------------------------------- */ boolean Ns3WaitForReqOff( pnin_softc DevExt ) { int baseAddress = DevExt->BaseAddress; u_long spinCount = REQUEST_SPIN_WAIT; u_char dataByte; do { dataByte = SCSI_READ(baseAddress, SCSIBUSMON); if ( !((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_REQ ) /* REQ Off ?*/ return TRUE; } while (spinCount--); /* must call scsi_done()? */ Ns3DebugPrint(0x04, ("TIMEOUT\n")); /* if (DevExt->ActiveUnit) { ScsiPortLogError(DevExt, DevExt->ActiveUnit->ActiveCommand, DevExt->ActiveUnit->ActiveCommand->PathId, DevExt->ActiveUnit->ActiveCommand->TargetId, DevExt->ActiveUnit->ActiveCommand->Lun, SP_REQUEST_TIMEOUT, 17); } */ Ns3NotifyCompletion(DevExt, DID_TIME_OUT); return FALSE; } /* end Ns3WaitForReqOff()*/ /* //----------------------------------------------------------------------------- // RESELECTION //----------------------------------------------------------------------------- */ boolean Ns3ProcessReselection( IN pnin_softc DevExt ) { /* u_char pathId = 0;*/ PSPECIFIC_LU_EXTENSION luExtension; Scsi_Cmnd *srb; PSPECIFIC_TARGET_EXTENSION targetState; int baseAddress = DevExt->BaseAddress; u_char dataByte; targetState = &DevExt->TargetState[DevExt->TargetId]; /**/ /* Get the specific logical unit extension.*/ /**/ Ns3DebugPrint(0x008,(KERN_DEBUG "Ns3ProcessReselection \n")); luExtension = ScsiPortGetLogicalUnit(/*DevExt,pathId,*/ DevExt->TargetId, /* DevExt->sc_link.target,//argetId,*/ DevExt->TargetLun); /* sc_link.lun ->TargetLun );*/ DevExt->ActiveUnit = luExtension; if (!luExtension || !luExtension->ActiveCommand) { /* SP_INVALID_RESELECTION ErrorCode,*/ Ns3DebugPrint(0x10,(KERN_DEBUG "Reselection Failed.\n")); /* // Send an abort message. Put the message-in the buffer, set the // state, indicate that a disconnect is expected after this, and // set the attention signal. */ DevExt->MessageBuffer[0] = MSG_ABORT; DevExt->MessageCount = 1; /* DevExt->AdapterState = MessageOut;*/ /* DevExt->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;*/ /* DevExt->AdapterFlags |= PD_MESSAGE_OUT_VALID |*/ /* PD_DISCONNECT_EXPECTED;*/ /* // // The target and logical unit specified are not valid. A // MESSAGE REJECT message has been set up. Set ATN and accept the // message. // */ dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); /* ATN ON !-> send-mdg mode*/ ((PSCSI_BUS_CONTROL)&dataByte)->ScsiATN = 1; /* ACK Off !*/ ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); Ns3NotifyCompletion(DevExt,DID_BUS_BUSY); return(FALSE); } Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3ProResel: Resel Start ID=%d\n", DevExt->TargetId)); srb = luExtension->ActiveCommand; #ifdef MUST_USEIO8 ((PTRANSFER_MODE)&DevExt->TransferMode)->AdrData24 = 0; ((PTRANSFER_MODE)&DevExt->TransferMode)->MemMap8 = 0; ((PTRANSFER_MODE)&DevExt->TransferMode)->MemMap16_32 = 0; ((PTRANSFER_MODE)&DevExt->TransferMode)->AdrData32 = 0; ((PTRANSFER_MODE)&DevExt->TransferMode)->IO8 = 1; ((PTRANSFER_MODE)&DevExt->TransferMode)->IO16_32 = 0; #endif /* 0630 */ Ns3SetTransferMode( DevExt ); /* TransferModeSet*/ /* // // A reselection has been completed. Set the active logical unit, // restore the active data pointer, set the state. // In addition, any adapter flags set by a pending select must be // cleared using the disconnect mask. // */ DevExt->CurDataPointer = luExtension->SavedDataPointer; DevExt->CurDataLength = luExtension->SavedDataLength; DevExt->MessageCount = 0; dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL); ((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; /* ACK Off !*/ SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); return(TRUE); } boolean Ns3MessageDecode( IN pnin_softc DevExt ) { Scsi_Cmnd *srb = DevExt->ActiveUnit->ActiveCommand; PSPECIFIC_TARGET_EXTENSION targetState = &DevExt->TargetState[srb ->target]; PSCSI_EXMSG exMsg; long offset; long i; /* u_long savedAdapterFlags;*/ exMsg = (PSCSI_EXMSG)DevExt->MessageBuffer; switch (exMsg->MessageType) { case SCSIMESS_MODIFY_DATA_POINTER: /**/ /* Verify the message length.*/ /**/ if (exMsg->MessageLength != SCSIMESS_MODIFY_DATA_LENGTH) { /**/ /* Reject the message.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } /**/ /* Calculate the modification to be added to the data pointer.*/ /**/ offset = 0; for (i = 0; i < 4; i++) { /* ???? offset << 8;*/ offset += exMsg->ExArg.MODIFY.modifier[i]; } /**/ /* Verify that the new data pointer is still within the range*/ /* of the buffer.*/ /**/ if (DevExt->CurDataLength - offset > /* srb->DataTransferLength ||*/ srb->request_bufflen ||/*srb->datalen ||*/ ((long) DevExt->CurDataLength - offset) < 0 ) { /**/ /* The new pointer is not valid, so reject the message.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } /**/ /* Everything has checked out, so update the pointer.*/ /**/ DevExt->CurDataPointer += offset; DevExt->CurDataLength -= offset; /**/ /* Everything is ok, so accept the message as is.*/ /**/ DevExt->MessageCount = 0; DevExt->ScsiState = SC_COMPLETE_OK; /*MessageAccepted;*/ return(FALSE); case SCSIMESS_SYNCHRONOUS_DATA_REQ: /**/ /* A SYNCHRONOUS DATA TRANSFER REQUEST message was received.*/ /* Make sure the length is correct.*/ /**/ if ( exMsg->MessageLength != SCSIMESS_SYNCH_DATA_LENGTH) { /**/ /* The length is invalid reject the message.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } /**/ /* If synchrouns negotiation has been disabled for this request,*/ /* then reject any synchronous messages; however, when synchronous*/ /* transfers are allowed then a new attempt can be made.*/ /**/ if (srb != NULL && !(targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) /* && srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER*/ ) { /**/ /* Reject the synchronous transfer message since synchonrous*/ /* transfers are not desired at this time.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } /**/ /* Call WdDecodeSynchronousMessage to decode the message and*/ /* formulate a response if necessary.*/ /* NcrDecodeSynchronousRequest will return FALSE if the*/ /* message is not accepable and should be rejected.*/ /**/ if (!Ns3DecodeSynchronousRequest( DevExt, targetState, srb->target, (boolean)!(targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) )) { /**/ /* Indicate that a negotiation has been done in the logical*/ /* unit and clear the negotiation flags.*/ /**/ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE; targetState->TargetFlags &=~(PD_SYNCHRONOUS_TRANSFER_SENT); /**/ /* The message was not acceptable so send a MESSAGE_REJECT.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } /**/ /* If a reponse was expected, then set the state for a message-out.*/ /* Otherwise, NcrDecodeSynchronousRequest has put a reponse*/ /* in the message buffer to be returned to the target.*/ /**/ if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT){ /**/ /* We initiated the negotiation, so no response is necessary.*/ /**/ targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT; targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE; return(FALSE); } /**/ /* Set up the state to send the reponse. The message count is*/ /* still correct.*/ /**/ DevExt->ScsiState = SC_MSG_OUT;/* MessageOut;*/ targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT; return(TRUE); case SCSIMESS_WIDE_DATA_REQUEST: /**/ /* A WIDE DATA TRANSFER REQUEST message was received.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); default: /**/ /* This is an unknown or illegal message, so send message REJECT.*/ /**/ DevExt->MessageCount = 1; DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT; return(TRUE); } } /* //----------------------------------------------------------------------------- // SYNCHRONOUS_DATA_REQ // //Routine Description: Ns3DecodeSynchronousRequest // // This function decodes the synchronous data transfer request message from // the target. It will update the synchronous message in the buffer and the // synchronous transfer parameters in the logical unit extension. These // parameters are specific for the WD 53C9X protocol chip. The updated // message in the device extension message buffer might be returned to the // target. // // This function should be called before the final byte of the message is // accepted from the SCSI bus. // //Arguments: // // DevExt - Supplies a pointer to the adapter-specific device // extension. // // LuExtension - Supplies a pointer to the logical unit's device extension. // The synchronous transfer fields are updated in this structure to // reflect the new parameter in the message. // // ResponseExpected - When set, indicates that the target initiated the // negotiation and that it expects a response. // //Return Value: // // TRUE - Returned if the request is acceptable. // // FALSE - Returned if the request should be rejected and a synchronous // transfer should be used. // //----------------------------------------------------------------------------- */ boolean Ns3DecodeSynchronousRequest( IN pnin_softc DevExt, PSPECIFIC_TARGET_EXTENSION TargetState, IN u_char TargetID, IN boolean ResponseExpected ) { PSCSI_EXMSG exMsg; long period; long i; u_char dataByte; exMsg = (PSCSI_EXMSG) DevExt->MessageBuffer; /**/ /* Determine the transfer offset. It is the minimum of the SCSI protocol*/ /* chip's maximum offset and the requested offset.*/ /**/ if (exMsg->ExArg.SYNCS.ReqAckOffset > SYNCHRONOUS_OFFSET) { if (!ResponseExpected) { /**/ /* The negotiation failed for some reason, fall back to*/ /* asynchronous data transfer.*/ /**/ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; TargetState->AckWidth = 0; return(FALSE); } exMsg->ExArg.SYNCS.ReqAckOffset = SYNCHRONOUS_OFFSET; TargetState->SynchronousOffset = SYNCHRONOUS_OFFSET; } else { TargetState->SynchronousOffset = exMsg->ExArg.SYNCS.ReqAckOffset; } /**/ /* If the offset requests asynchronous transfers then set the default*/ /* period and return.*/ /**/ if (exMsg->ExArg.SYNCS.ReqAckOffset == ASYNCHRONOUS_OFFSET) { TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; TargetState->AckWidth = 0; return(TRUE); } /**/ /* Check to see if the period is less than the SCSI protocol chip can*/ /* use. If it is then update the message with our minimum and return.*/ /**/ if (exMsg->ExArg.SYNCS.TransferPeriod < SYNCHRONOUS_PERIOD ) { if (!ResponseExpected) { /**/ /* The negotiation failed for some reason, fall back to*/ /* asynchronous data transfer.*/ /**/ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; TargetState->AckWidth = 0; return(FALSE); } exMsg->ExArg.SYNCS.TransferPeriod = SYNCHRONOUS_PERIOD; } period = exMsg->ExArg.SYNCS.TransferPeriod; for ( i=0; i= SyncTable[i].StartPeriod) && (period <= SyncTable[i].EndPeriod) ) break; } if (i >= SYNC_TABLE_MAX) { /**/ /* The requested transfer period is too long for the SCSI protocol*/ /* chip. Fall back to synchronous and reject the request.*/ /**/ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET; TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD; TargetState->AckWidth = 0; return(FALSE); } else { TargetState->SynchronousPeriod = SyncTable[i].TransferPeriod; TargetState->AckWidth = SyncTable[i].AckWidth; } /**/ /* Set the synchronous data transfer parameter registers*/ /* to the new values. These must be set before a data transfer*/ /* is started. If a response message is received then the parameters*/ /* must be reset.*/ /**/ dataByte = 0; ((PSYNC_REG)&dataByte)->SyncPeriod = TargetState->SynchronousPeriod; ((PSYNC_REG)&dataByte)->SyncOffset = TargetState->SynchronousOffset; SCSI_WRITE( DevExt->BaseAddress, ACKWIDTH,TargetState->AckWidth); SCSI_WRITE( DevExt->BaseAddress, SYNCREG ,dataByte); return(TRUE); } #ifdef DBG_SHOWCOMMAND /* * Show the command data of a command */ static const char unknown[] = "UNKNOWN"; static const char * group_0_commands[] = { /* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", /* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, }; static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, /* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", /* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", /* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", /* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, /* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown, /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, /* 5c-5f */ unknown, unknown, unknown, }; #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 #define NOTEXT_GROUP 2 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; static const char reserved[] = "RESERVED"; static const char vendor[] = "VENDOR SPECIFIC"; static void print_opcodek(int opcode) { const char **table = commands[ group(opcode) ]; switch ((unsigned long) table) { case RESERVED_GROUP: printk(KERN_DEBUG "%s(0x%02x) ", reserved, opcode); break; case NOTEXT_GROUP: printk(KERN_DEBUG "%s(0x%02x) ", unknown, opcode); break; case VENDOR_GROUP: printk(KERN_DEBUG "%s(0x%02x) ", vendor, opcode); break; default: if (table[opcode & 0x1f] != unknown) printk(KERN_DEBUG "%s ",table[opcode & 0x1f]); else printk(KERN_DEBUG "%s(0x%02x) ", unknown, opcode); break; } } void print_commandk (unsigned char *command) { int i,s; print_opcodek(command[0]); for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) { printk(KERN_DEBUG "%02x ", command[i]); } printk(KERN_DEBUG "\n"); } /************** delete after ******************************/ static void show_command(Scsi_Cmnd *ptr) { print_commandk(ptr->cmnd); printk(KERN_DEBUG "); residual=%d; buffers=%d; phase |", ptr->SCp.this_residual, ptr->SCp.buffers_residual); if(ptr->SCp.phase & not_issued ) printk(KERN_DEBUG "not issued|"); if(ptr->SCp.phase & in_selection) printk(KERN_DEBUG "in selection|"); if(ptr->SCp.phase & disconnected) printk(KERN_DEBUG "disconnected|"); if(ptr->SCp.phase & aborted ) printk(KERN_DEBUG "aborted|"); if(ptr->SCp.phase & sent_ident ) printk(KERN_DEBUG "send_ident|"); if(ptr->SCp.phase == 0) { printk(KERN_DEBUG "; phase[%x] (",ptr->SCp.phase); } if(ptr->SCp.phase & in_other) { printk(KERN_DEBUG "; in other("); switch((ptr->SCp.phase >> 16) & P_MASK) { case P_DATAO: printk(KERN_DEBUG "DATA OUT"); break; case P_DATAI: printk(KERN_DEBUG "DATA IN"); break; case P_CMD: printk(KERN_DEBUG "COMMAND"); break; case P_STATUS: printk(KERN_DEBUG "STATUS"); break; case P_MSGO: printk(KERN_DEBUG "MESSAGE OUT"); break; case P_MSGI: printk(KERN_DEBUG "MESSAGE IN"); break; default: printk(KERN_DEBUG "*illegal*"); break; } printk(KERN_DEBUG ")"); if(ptr->SCp.phase & (1<<16)) printk(KERN_DEBUG "; phaseend"); } printk(KERN_DEBUG "; next=0x%08x\n", (unsigned int) ptr->host_scribble); } /************** delete after ******************************/ #endif /* DBG_SHOWCOMMAND */ /*====================================================================*/ static void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; CardServices(ReportError, handle, &err); } /*====================================================================== ninja3_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. The dev_link structure is initialized, but we don't actually configure the card at this point -- we wait until we receive a card insertion event. ======================================================================*/ #ifdef USE_IRQ_HANDLE_PRESENT static void ninja3_interrupt2 IRQ(int irq, void *dev_id, struct pt_regs *regs) { ninja3_interrupt((void *)irq); } #endif static dev_link_t *ninja3_attach(void) { client_reg_t client_reg; dev_link_t *link; /* local_info_t scsi_info_t *local; */ int ret; DEBUG(0, "ninja3_attach()\n"); /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); memset(link, 0, sizeof(struct dev_link_t)); /* Create new SCSI device */ link->priv = kmalloc(sizeof(struct scsi_info_t), GFP_KERNEL); memset(link->priv, 0, sizeof(struct scsi_info_t)); /* Create new SCSI device */ link->release.function = &ninja3_release; link->release.data = (u_long)link; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; /* link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */ link->io.IOAddrLines = 5; /* not used */ /* Interrupt setup */ #ifdef USE_IRQ_HANDLE_PRESENT link->irq.Attributes = IRQ_TYPE_EXCLUSIVE| IRQ_HANDLE_PRESENT; #else link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; #endif link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; link->irq.IRQInfo2 = irq_mask; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; #ifdef USE_IRQ_HANDLE_PRESENT link->irq.Handler = &ninja3_interrupt2; #endif /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &ninja3_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); ninja3_detach(link); return NULL; } return link; } /* ninja3_attach */ /*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released. ======================================================================*/ static void ninja3_detach(dev_link_t *link) { dev_link_t **linkp; DEBUG(0, "ninja3_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; /* If the device is currently configured and active, we won't actually delete it yet. Instead, it is marked so that when the release() function is called, that will trigger a proper detach(). */ if (link->state & DEV_CONFIG) { #ifdef PCMCIA_DEBUG Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_cs: detach postponed, '%s' still locked\n", link->dev->dev_name)); #endif link->state |= DEV_STALE_LINK; return; } /* Break the link with Card Services */ if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; if (link->priv) { kfree_s(link->priv, sizeof(local_info_t)); } kfree_s(link, sizeof(struct dev_link_t)); } /* ninja3_detach */ /*====================================================================== ninja3_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. ======================================================================*/ #define CS_CHECK(fn, args...) \ while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed /*====================================================================*/ static void ninja3_config(dev_link_t *link) { client_handle_t handle; scsi_info_t *info; tuple_t tuple; cisparse_t parse; int i; u_char tuple_data[64]; #ifdef GET_SCSI_INFO Scsi_Device *dev; dev_node_t **tail, *node; #endif handle = link->handle; info = link->priv; tuple.TupleData = tuple_data; tuple.TupleDataMax = 0x75; /* ORESAMA */ tuple.TupleOffset = 0; do { tuple.DesiredTuple = CISTPL_CONFIG; i = CardServices(GetFirstTuple, handle, &tuple); if (i != CS_SUCCESS) break; i = CardServices(GetTupleData, handle, &tuple); if (i != CS_SUCCESS) break; i = CardServices(ParseTuple, handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); if (i != CS_SUCCESS) { cs_error(link->handle, ParseTuple, i); link->state &= ~DEV_CONFIG_PENDING; return; } /* Configure card */ link->state |= DEV_CONFIG; #ifdef MODULE driver_template.usage_count = &mod_use_count_; #endif do { tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; i = CardServices(GetFirstTuple, handle, &tuple); while (i == CS_SUCCESS) { i = CardServices(GetTupleData, handle, &tuple); if (i != CS_SUCCESS) break; i = CardServices(ParseTuple, handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.BasePort1 = 0x240; // ORESAMA if (link->io.BasePort1 != 0) { i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } i = CardServices(GetNextTuple, handle, &tuple); } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); break; } i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle,RequestIRQ, i); break; } /* */ i = CardServices(RequestConfiguration, link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); break; } } while (0); if (i != 0) { ninja3_release((u_long)link); return; } /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set port and IRQ */ mbase=link->io.BasePort1 ; mpirq=link->irq.AssignedIRQ/*-1*/; Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_config[%x]\n",mbase)); if( !Ns3Initialize(0) ){ /* ORESAMA*/ return ; } /* set sg_tablesize */ if( sg_tablesize >0 && sg_tablesize <= 64 ) { driver_template.sg_tablesize = sg_tablesize; } scsi_register_module(MODULE_SCSI_HA, &driver_template); #ifdef GET_SCSI_INFO Ns3DebugPrint(0x10,(KERN_DEBUG "GET_SCSI_INFO\n")); tail = &link->dev; info->ndev = 0; for (dev = scsi_devices; dev != NULL; dev = dev->next) if (dev->host->hostt == &driver_template) { u_long arg[2], id; kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); node = &info->node[info->ndev]; node->minor = 0; switch (dev->type) { case TYPE_TAPE: node->major = SCSI_TAPE_MAJOR; sprintf(node->dev_name, "st#%04lx", id); break; case TYPE_DISK: case TYPE_MOD: node->major = SCSI_DISK_MAJOR; sprintf(node->dev_name, "sd#%04lx", id); break; case TYPE_ROM: case TYPE_WORM: node->major = SCSI_CDROM_MAJOR; sprintf(node->dev_name, "sr#%04lx", id); break; default: node->major = SCSI_GENERIC_MAJOR; sprintf(node->dev_name, "sg#%04lx", id); break; } *tail = node; tail = &node->next; /*0626*/ info->ndev++; } *tail = NULL; if (info->ndev == 0) { Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_cs: no SCSI devices found\n")); } #else strcpy(info->node[0].dev_name, "n/a"); link->dev = &info->node[0]; #endif /* GET_SCSI_INFO */ link->state &= ~DEV_CONFIG_PENDING; } /* ninja3_config */ /*====================================================================== After a card is removed, ninja3_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/ static void ninja3_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; /*local_info_t scsi_info_t *local = link->priv; */ DEBUG(0, "ninja3_release(0x%p)\n", link); /* If the device is currently in use, we won't release until it is actually closed. */ if (link->open) { DEBUG(1, "ninja3_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } /* Unlink the device chain */ scsi_unregister_module(MODULE_SCSI_HA, &driver_template); link->dev = NULL; /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseWindow, link->win); CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) ninja3_detach(link); } /* ninja3_release */ /*====================================================================== The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the net drivers from trying to talk to the card any more. When a CARD_REMOVAL event is received, we immediately set a flag to block future accesses to this device. All the functions that actually access the device should check this flag to make sure the card is still present. ======================================================================*/ static int ninja3_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; DEBUG(1, "ninja3_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { /* ((scsi_info_t)link->priv)->block = 1;*/ link->release.expires = RUN_AT(HZ/20); add_timer(&link->release); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ninja3_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) CardServices(ReleaseConfiguration, link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); /* ninja3_reset(NULL); */ } break; } Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_event end\n")); return 0; } /* ninja3_event */ /*======================================================================*/ /*====================================================================*/ int init_module(void) { servinfo_t serv; DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_DEBUG "Ninja3: Card Services release " "does not match!\n"); return -1; } register_pcmcia_driver(&dev_info, &ninja3_attach, &ninja3_detach); return 0; } void cleanup_module(void) { DEBUG(0, "ninja3_cs: unloading\n"); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) ninja3_release((u_long)dev_list); ninja3_detach(dev_list); } } /* * * */ /*----------------------------------------------------------------*/ /* look for ninja3 card and init if found */ /*----------------------------------------------------------------*/ int ninja3_detect(Scsi_Host_Template * host) { struct Scsi_Host *hreg; /* registered host structure */ #if (LINUX_VERSION_CODE > VERSION(1,2,13)) host->proc_dir = &proc_scsi_ninja3; #endif minitid = host->this_id; if (minitid < 0) minitid = 7; /* if no ID, use 7 */ Ns3DebugPrint(0x10,(KERN_DEBUG "mbase[%x] minitid[%x] irq[%x]\n",mbase,minitid,mpirq)); Ns3DebugPrint(0x10,( "ninja3_detect ninja3_detect mbase[%x] minitid[%x] irq[%x]\n",mbase,minitid,mpirq)); request_region( mbase , 0x10 ,"ninja3"); hreg = scsi_register( host , 0 ); /* no host data */ hreg->io_port = mbase; hreg->n_io_port = 16; hreg->dma_channel = -1; if( mpirq != -1 ) hreg->irq = mpirq; sprintf(minfo, "NinjaSCSI-3 Driver version 0.10, iobase at %03X", mbase ); host->name = minfo; Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_detect end\n")); Ns3DebugPrint(0x10,("ninja3_detect end\n")); return 1; } /*----------------------------------------------------------------*/ /* return info string */ /*----------------------------------------------------------------*/ const char *ninja3_info(struct Scsi_Host * host) { return minfo; } /*----------------------------------------------------------------*/ /* abort command in progress */ /*----------------------------------------------------------------*/ int ninja3_abort(Scsi_Cmnd * cmd) { mabort = 1; /* mp_zap(); */ Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_abort\n")); return 0; } /*----------------------------------------------------------------*/ /* reset SCSI bus */ /*----------------------------------------------------------------*/ int ninja3_reset(Scsi_Cmnd * cmd) { mabort = 2; /* mp_zap(); */ Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_reset\n")); Ns3ResetScsiBus( nin_data ); cmd->result = DID_RESET << 16; cmd->scsi_done(cmd); mabort = 0; return 1; }