Beispiel #1
0
/*  send a command or parameter to the drive
 *  Generates # of step pulses.
 */
static inline int ft_send_to_drive(int arg)
{
	/*  Always wait for a command_timeout period to separate
	 *  individuals commands and/or parameters.
	 */
	ftape_sleep(3 * FT_MILLISECOND);
	/*  Keep cylinder nr within range, step towards home if possible.
	 */
	if (ftape_current_cylinder >= arg) {
		return fdc_seek(ftape_current_cylinder - arg);
	} else {
		return fdc_seek(ftape_current_cylinder + arg);
	}
}
/**************************************************************************
* int fdc_fdos_seek
* parameter is a block number
*/
int fdc_fdos_seek (int where)
{
	FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
	FDC_COMMAND_STRUCT *pCMD = &cmd;

	pCMD -> blnr = where ;
	return (fdc_seek (pCMD, pFG));
}
Beispiel #3
0
	void fdc_read(int cyl,int head,int sect,int seccount)
	{
		//char cmd[9]={READ_DATA,head<<2,cyl,head,sect,2,seccount,0x1b,0xff};
		char cmd[9]={0xe6,head<<2,cyl,head,sect,0x02,0x12,1,0xff};
		for(int i=0;i<5;i++)
		{
			send_fdc_cmd(cmd,9);
			while(!fdc_inted)io_hlt();
			fdc_inted=false;
			char res[7];
			get_fdc_cmd(res,7);
			int result=check_st0(res[0]);
			if(result == 0)break;
			fdc_recalibrate();
			fdc_seek(cyl,head);
		}
	}
Beispiel #4
0
/* --- Main FDC dispatcher --- */
static void fdc_execute(FDC_765 *self)
{
/* This code to dump out FDC commands as they are received is very useful
 * in debugging
 *
 * */
	int NC;
	fdc_dprintf(5, "FDC: ");
	for (NC = 0; NC < bytes_in_cmd[self->fdc_cmd_buf[0] & 0x1F]; NC++)
		fdc_dprintf(5, "%02x ", self->fdc_cmd_buf[NC]);
	fdc_dprintf(5, "\n");
 /* */
	/* Check if the DOR (ugh!) is being used to force us to a 
	   different drive. */
	fdc_dorcheck(self);

	/* Reset "seek finished" flag */
	self->fdc_st0 &= 0xBF;	 
	switch(self->fdc_cmd_buf[0] & 0x1F)
	{
		case 2: fdc_read_track(self);	break;	/* 2: READ TRACK */
		case 3: fdc_specify(self);	break;	/* 3: SPECIFY */
		case 4:	fdc_sense_drive(self);	break;	/* 4: SENSE DRV STATUS*/
		case 5:	fdc_write(self, 0);	break;	/* 5: WRITE */
		case 6: fdc_read(self, 0);	break;	/* 6: READ */
		case 7:	fdc_recalibrate(self);	break;	/* 7: RECALIBRATE */
		case 8: fdc_sense_int(self);	break;	/* 8: SENSE INT STATUS*/
		case 9: fdc_write(self, 1);	break;	/* 9: WRITE DELETED */
		case 10:fdc_read_id(self);	break;	/*10: READ ID */
		case 12:fdc_read(self, 1);	break;	/*12: READ DELETED */
		case 13:fdc_format(self);	break;	/*13: FORMAT TRACK */
		case 15:fdc_seek(self);		break;	/*15: SEEK */
		case 17:				/*17: SCAN EQUAL */
		case 25:				/*25: SCAN LOW/EQUAL */
		case 30:fdc_scan(self);		break;	/*30: SCAN HIGH/EQUAL*/
		default:
			fdc_dprintf(2, "Unknown FDC command %d\n", 
					self->fdc_cmd_buf[0] & 0x1F);
			fdc_error(self);	break;
	}

}
/* Scan all drives and check if drive is present and disk is inserted */
int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
{
	int i,drives,state;
  /* OK procedure of data book is satisfied.
	 * trying to get some information over the drives */
	state=0; /* no drives, no disks */
	for(drives=0;drives<4;drives++) {
		pCMD->drive=drives;
		select_fdc_drive(pCMD);
		pCMD->blnr=0; /* set to the 1st block */
		if(fdc_recalibrate(pCMD,pFG)==FALSE)
			continue;
		if((pCMD->result[STATUS_0]&0x10)==0x10)
			continue;
		/* ok drive connected check for disk */
		state|=(1<<drives);
		pCMD->blnr=pFG->size; /* set to the last block */
		if(fdc_seek(pCMD,pFG)==FALSE)
			continue;
		pCMD->blnr=0; /* set to the 1st block */
		if(fdc_recalibrate(pCMD,pFG)==FALSE)
			continue;
		pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
		if(fdc_issue_cmd(pCMD,pFG)==FALSE)
			continue;
		state|=(0x10<<drives);
	}
	stop_fdc_drive(pCMD);
	for(i=0;i<4;i++) {
		PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
			((state&(1<<i))==(1<<i)) ? "":"not ",
			((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
			((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
	}
	pCMD->flags=state;
	return TRUE;
}
/* reads data from FDC, seek commands are issued automatic */
int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
{
  /* first seek to start address */
	unsigned long len,lastblk,readblk,i,timeout,ii,offset;
	unsigned char pcn,c,retriesrw,retriescal;
	unsigned char *bufferw; /* working buffer */
	int sect_size;
	int flags;

	flags=disable_interrupts(); /* switch off all Interrupts */
	select_fdc_drive(pCMD); /* switch on drive */
	sect_size=0x080<<pFG->sect_code;
	retriesrw=0;
	retriescal=0;
	offset=0;
	if(fdc_seek(pCMD,pFG)==FALSE) {
		stop_fdc_drive(pCMD);
		enable_interrupts();
		return FALSE;
	}
	if((pCMD->result[STATUS_0]&0x20)!=0x20) {
		printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
		stop_fdc_drive(pCMD);
		enable_interrupts();
		return FALSE;
	}
	pcn=pCMD->result[STATUS_PCN]; /* current track */
	/* now determine the next seek point */
	lastblk=pCMD->blnr + blocks;
	/*	readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
	readblk=pFG->sect-(pCMD->blnr%pFG->sect);
	PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr);
	if(readblk>blocks) /* is end within 1st track */
		readblk=blocks; /* yes, correct it */
	PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr);
	bufferw=&buffer[0]; /* setup working buffer */
	do {
retryrw:
		len=sect_size * readblk;
		pCMD->cmd[COMMAND]=FDC_CMD_READ;
		if(fdc_issue_cmd(pCMD,pFG)==FALSE) {
			stop_fdc_drive(pCMD);
			enable_interrupts();
			return FALSE;
		}
		for (i=0;i<len;i++) {
			timeout=FDC_TIME_OUT;
			do {
				c=read_fdc_reg(FDC_MSR);
				if((c&0xC0)==0xC0) {
					bufferw[i]=read_fdc_reg(FDC_FIFO);
					break;
				}
				if((c&0xC0)==0x80) { /* output */
					PRINTF("Transfer error transfered: at %ld, MSR=%02X\n",i,c);
					if(i>6) {
						for(ii=0;ii<7;ii++) {
							pCMD->result[ii]=bufferw[(i-7+ii)];
						} /* for */
					}
					if(retriesrw++>FDC_RW_RETRIES) {
						if (retriescal++>FDC_CAL_RETRIES) {
							stop_fdc_drive(pCMD);
							enable_interrupts();
							return FALSE;
						}
						else {
							PRINTF(" trying to recalibrate Try %d\n",retriescal);
							if(fdc_recalibrate(pCMD,pFG)==FALSE) {
								stop_fdc_drive(pCMD);
								enable_interrupts();
								return FALSE;
							}
							retriesrw=0;
							goto retrycal;
						} /* else >FDC_CAL_RETRIES */
					}
					else {
						PRINTF("Read retry %d\n",retriesrw);
						goto retryrw;
					} /* else >FDC_RW_RETRIES */
				}/* if output */
				timeout--;
			}while(TRUE);
		} /* for len */
		/* the last sector of a track or all data has been read,
		 * we need to get the results */
		fdc_terminate(pCMD);
		offset+=(sect_size*readblk); /* set up buffer pointer */
		bufferw=&buffer[offset];
		pCMD->blnr+=readblk; /* update current block nr */
		blocks-=readblk; /* update blocks */
		if(blocks==0)
			break; /* we are finish */
		/* setup new read blocks */
		/*	readblk=pFG->head*pFG->sect; */
		readblk=pFG->sect;
		if(readblk>blocks)
			readblk=blocks;
retrycal:
		/* a seek is necessary */
		if(fdc_seek(pCMD,pFG)==FALSE) {
			stop_fdc_drive(pCMD);
			enable_interrupts();
			return FALSE;
		}
		if((pCMD->result[STATUS_0]&0x20)!=0x20) {
			PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
			stop_fdc_drive(pCMD);
			return FALSE;
		}
		pcn=pCMD->result[STATUS_PCN]; /* current track */
	}while(TRUE); /* start over */
	stop_fdc_drive(pCMD); /* switch off drive */
	enable_interrupts();
	return TRUE;
}
Beispiel #7
0
void fdc_recalib(void)
{
    FDC.command[CMD_C] = 0; // seek to track 0
    fdc_seek();
}
Beispiel #8
0
void t_FDC::fdc_recalib()
{
	command[CMD_C] = 0; // seek to track 0
	fdc_seek();
}
Beispiel #9
0
void fdc_write(unsigned char a) { // Write byte to data register
	static int cmdlen = 9; // length of FDC command
#ifdef FDC_DEBUG	
	printf("FDC DATA WRITE = 0x%x\n", a);
#endif	
	switch(phase) {
		case P_COMMAND:
			fdccommand[CmdByte] = a; // store part of command
			if (CmdByte == 0) { // first byte of command
				switch(a&0x1F) {
					case CMD_READDATA:
					case CMD_READDELETEDDATA:
					case CMD_WRITEDATA:
					case CMD_WRITEDELETEDDATA:
					case CMD_READDIAGNOSTIC:
					case CMD_SCANEQUAL:
					case CMD_SCANLOWEQUAL:
					case CMD_SCANHIGHEQUAL:
						cmdlen = 9;
						break;
					case CMD_WRITEID:
						cmdlen = 6;
						break;
					case CMD_SPECIFY:
					case CMD_SEEK:
						cmdlen = 3;
						break;
					case CMD_READID:
					case CMD_RECALIBRATE:
					case CMD_SENSEDRV:
						cmdlen = 2;
						break;
					case CMD_SENSEINT:
					case CMD_VERSION:
						cmdlen = 1;
						break;
					default: // Invalid Command
						cmdlen = 1;
						printf("Invalid FDC Command received: 0x%x\n", a);
						break;	
				}
			// Set CB (Busy) flag
			//fdc_status_main|=MAIN_CB;	
			}
			CmdByte++;
			if (CmdByte == cmdlen) { // Command phase finished
				switch(fdccommand[0]&0x1F) {
					case CMD_READDATA:
						fdc_read_data();
						break;
					case CMD_READDELETEDDATA:
						printf("*** Unimplemented FDC Command READ DELETED DATA\n");
						break;
					case CMD_WRITEDATA:
						printf("*** Unimplemented FDC Command WRITE DATA\n");
						break;
					case CMD_WRITEDELETEDDATA:
						printf("*** Unimplemented FDC Command WRITE DELETED DATA\n");
						break;
					case CMD_READDIAGNOSTIC:
						printf("*** Unimplemented FDC Command READ DIAGNOSTIC\n");
						break;
					case CMD_READID:
						// Read sector ID
						fdc_read_id();
						break;
					case CMD_WRITEID:
						printf("*** Unimplemented FDC Command WRITE ID\n");
						break;
					case CMD_SCANEQUAL:
						printf("*** Unimplemented FDC Command SCAN EQUAL\n");
						break;
					case CMD_SCANLOWEQUAL:
						printf("*** Unimplemented FDC Command SCAN LOW OR EQUAL\n");
						break;
					case CMD_SCANHIGHEQUAL:
						printf("*** Unimplemented FDC Command SCAN HIGH OR EQUAL\n");
						break;
					case CMD_RECALIBRATE:
						// Reset to track 0
						fdc_seek(0);
						break;
					case CMD_SENSEINT:
						// Get Interrupt status register
						fdc_senseint();
						break;
					case CMD_SPECIFY:
						// We really don't need to do anything here. This command only sets
						// physical timing parameters. These are not relevant to a virtual FDC.
						fdc_status_main&=~MAIN_CB; // Clear CB (busy) flag
						break;
					case CMD_SENSEDRV:
						printf("*** Unimplemented FDC Command SENSE DRIVE\n");
						break;
					case CMD_VERSION:
						printf("*** Unimplemented FDC Command VERSION\n");
						break;
					case CMD_SEEK:
						// Seek to a specified track
						fdc_seek(fdccommand[2]);
						break;
					default:
						break;
				}
				CmdByte = 0;
			}
			break;
		case P_EXECUTION: // Execution phase
			break;
		case P_RESULT: // There should be no write acces in result phase
			break;
	}
}
Beispiel #10
0
/* If no request is currently being processed and there's new requests in
   the queue, process the first one. This can be called from an interrupt
   or the normal kernel context. */
void do_request(blkreq_t *req)
{
    fd_dev_t *dev;
    u_long track, sect, cyl, head, big_sect, sects;
    u_long flags;
    int i;

    save_flags(flags);

    /* This label is used to eliminate tail-recursion. */
top:

    cli();
    if(current_req != NULL)
    {
	if(req != NULL)
	    append_node(&fd_reqs, &req->node);
	load_flags(flags);
	return;
    }
    for(i = 0; i < 2; i++)
    {
	if(fd_devs[i].recalibrate)
	{
	    fdc_recal(&fd_devs[i]);
	    if(req != NULL)
		append_node(&fd_reqs, &req->node);
	    load_flags(flags);
	    return;
	}
    }
    if(req == NULL)
    {
	if(!list_empty_p(&fd_reqs))
	{
	    req = (blkreq_t *)fd_reqs.head;
	    remove_node(&req->node);
	}
	else
	{
	    load_flags(flags);
	    return;
	}
    }
    current_req = req;
#if 0
    req->retries = 0;
#endif
    load_flags(flags);

    dev = REQ_FD_DEV(req);

    DB(("fd:do_request: req=%p drive=%d block=%d nblocks=%d cmd=%d buf=%p\n",
	req, dev->drvno, req->block, req->nblocks, req->command, req->buf));

    switch(req->command)
    {
    case FD_CMD_SEEK:	/* We wanna MOVE DA HEAD! */
        /* Do da seek. */
	if(fdc_seek(dev, req->block) == FALSE)
	{
		handle_error("FD_CMD_SEEK, seek");
		goto top;
		break;
	}

	/* Then Sense Interrupt Status */
	if(fdc_sense() == FALSE)
	{
		handle_error("FD_CMD_SEEK, fdc_sense");
		goto top;
		break;
	}

	/* and now we have to Read the ID */
	if(fdc_read_id(dev) == FALSE)
	{
		handle_error("FD_CMD_SEEK, read_id");
		goto top;
		break;
	}

        fd_end_request(0);
	req = NULL;
        goto top;

    case FD_CMD_TIMER:
	fd_end_request(0);
	req = NULL;
	goto top;
    }

    if(req->block >= dev->total_blocks)
    {
	kprintf("fd: Device %s (%p) doesn't have a block %d!\n",
		dev->name, dev, req->block);
	fd_end_request(-1);
	req = NULL;
	goto top;
    }

    big_sect = req->block;
    sects = req->nblocks;

    track = big_sect / dev->disk_p->sectors;
    sect = big_sect % dev->disk_p->sectors + 1;
    head = track % dev->disk_p->heads;
    cyl = track / dev->disk_p->heads;

    DB(("fd:do_request: cyl=%d sect=%d head=%d sects=%d\n", cyl, sect, head, sects));

    switch(req->command)
    {
    case FD_CMD_READ:	/* We wanna READ the floppy! */

#if 0
        fd_end_request(0);
	req = NULL;
        goto top;
#endif

	/* We need to seek to the right cylinder. */
	if(fdc_seek(dev, cyl) == FALSE)
	{
		handle_error("FD_CMD_READ, seek");
		goto top;
		break;
	}

	/* Then Sense Interrupt Status */
	if(fdc_sense() == FALSE)
	{
		handle_error("FD_CMD_READ, fdc_sense");
		goto top;
		break;
	}

	/* and now we have to Read the ID */
	if(fdc_read_id(dev) == FALSE)
	{
		handle_error("FD_CMD_READ, read_id");
		goto top;
		break;
	}

#define TPA(XX) ((u_long)TO_PHYSICAL(XX))

	/* Tell the DMA what to do, and hope for the best! */
	/* Should move this inside fdc, in fdc_read() i think */
	DMAbuf.Buffer = track_buf;
	DMAbuf.Page = (u_int8)((TPA(track_buf) >> 16) & 0xff);
	DMAbuf.Offset = (u_int16)(TPA(track_buf) & 0xffff);
	DMAbuf.Len = (u_int16)(dev->disk_p->sectors * dev->disk_p->heads *
		FD_SECTSIZ) - 1;
	DMAbuf.Chan = FLOPPY_DMA;
	kernel->setup_dma(&DMAbuf, DMA_READ);

	/* Now we issue a read command. */
	if(fdc_read(dev, cyl) == FALSE)
	{
		handle_error("FD_CMD_READ, read");
		goto top;
		break;
	}

	break;

    case FD_CMD_WRITE:	/* We wanna WRITE it too! */

        fd_end_request(0);
	req = NULL;
        goto top;

    default:
	kprintf("fd:do_request: Unknown command in fd_req, %d\n",
		req->command);
	fd_end_request(-1);
	req = NULL;
	goto top;
    }
}