staticunsignedlong atari_dma_residual, atari_dma_startaddr; staticshort atari_dma_active; /* pointer to the dribble buffer */ staticchar *atari_dma_buffer; /* precalculated physical address of the dribble buffer */ staticunsignedlong atari_dma_phys_buffer; /* != 0 tells the Falcon int handler to copy data from the dribble buffer */ staticchar *atari_dma_orig_addr; /* size of the dribble buffer; 4k seems enough, since the Falcon cannot use *scatter-gatheranyway,somosttransfersare1024byteonly.Intherare *caseswhererequeststophysicalcontiguousbuffershavebeenmerged,this *requestis<=4k(onepage).SoIdon'tthinkwehavetosplittransfers *justduetothisbuffersize...
*/ #define STRAM_BUFFER_SIZE (4096) /* mask for address bits that can't be used with the ST-DMA */ staticunsignedlong atari_dma_stram_mask; #define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
/* Look if it was the DMA that has interrupted: First possibility *isthatabuserroroccurred...
*/ if (dma_stat & 0x80) { if (!scsi_dma_is_ignored_buserr(dma_stat)) {
printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
SCSI_DMA_READ_P(dma_addr));
printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
}
}
/* If the DMA is active but not finished, we have the case *thatsomeother5380interruptoccurredwithintheDMAtransfer. *Thismeanswehaveresidualbytes,ifthedesiredendaddress *isnotyetreached.Maybewehavetofetchsomebytesfromthe *restdataregister,too.Theresidualmustbecalculatedfrom *theaddresspointer,notthecounterregister,becauseonlythe *addrregcountsbytesnotyetwrittenandpendingintherest *datareg!
*/ if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
atari_dma_residual = hostdata->dma_len -
(SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
/* If the DMA is finished, fetch the rest bytes and turn it off */ if (dma_stat & 0x40) {
atari_dma_residual = 0; if ((dma_stat & 1) == 0)
atari_scsi_fetch_restbytes();
tt_scsi_dma.dma_ctrl = 0;
}
/* Turn off DMA and select sector counter register before *accessingthestatusregister(Atarirecommendation!)
*/
st_dma.dma_mode_status = 0x90;
dma_stat = st_dma.dma_mode_status;
/* Bit 0 indicates some error in the DMA process... don't know *whathappenedexactly(nofurtherdocu).
*/ if (!(dma_stat & 0x01)) { /* DMA error */
printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR());
}
/* If the DMA was active, but now bit 1 is not clear, it is some *other5380interruptthatfinishestheDMAtransfer.Wehaveto *calculatethenumberofresidualbytesandgiveawarningif *bytesarestuckintheST-DMAfifo(there'snowaytoreachthem!)
*/ if (atari_dma_active && (dma_stat & 0x02)) { unsignedlong transferred;
transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; /* The ST-DMA address is incremented in 2-byte steps, but the *dataarewrittenonlyin16-bytechunks.Ifthenumberof *transferredbytesisnotdivisibleby16,theremainderis *lostsomewhereinouterspace.
*/ if (transferred & 15)
printk(KERN_ERR "SCSI DMA error: %ld bytes lost in " "ST-DMA fifo\n", transferred & 15);
if (atari_dma_orig_addr) { /* If the dribble buffer was used on a read operation, copy the DMA-ed *datatotheoriginaldestinationaddress.
*/
memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),
hostdata->dma_len - atari_dma_residual);
atari_dma_orig_addr = NULL;
}
NCR5380_intr(irq, dev);
return IRQ_HANDLED;
}
staticvoid atari_scsi_fetch_restbytes(void)
{ int nr; char *src, *dst; unsignedlong phys_dst;
/* fetch rest bytes in the DMA register */
phys_dst = SCSI_DMA_READ_P(dma_addr);
nr = phys_dst & 3; if (nr) { /* there are 'nr' bytes left for the last long address
before the DMA pointer */
phys_dst ^= nr;
dprintk(NDEBUG_DMA, "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
nr, phys_dst); /* The content of the DMA pointer is a physical address! */
dst = phys_to_virt(phys_dst);
dprintk(NDEBUG_DMA, " = virt addr %p\n", dst); for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr)
*dst++ = *src++;
}
}
/* This function releases the lock on the DMA chip if there is no *connectedcommandandthedisconnectedqueueisempty.
*/
staticvoid falcon_release_lock(void)
{ if (IS_A_TT()) return;
if (stdma_is_locked_by(scsi_falcon_intr))
stdma_release();
}
/* This function manages the locking of the ST-DMA. *IftheDMAisn'tlockedalreadyforSCSI,ittriestolockitby *callingstdma_lock().ButiftheDMAislockedbytheSCSIcodeand *thereareotherdriverswaitingforthechip,wedonotissuethe *commandimmediatelybuttelltheSCSImid-layertodefer.
*/
staticint falcon_get_lock(struct Scsi_Host *instance)
{ if (IS_A_TT()) return1;
if (stdma_is_locked_by(scsi_falcon_intr)) return1;
/* stdma_lock() may sleep which means it can't be used here */ return stdma_try_lock(scsi_falcon_intr, instance);
}
#ifndef MODULE staticint __init atari_scsi_setup(char *str)
{ /* Format of atascsi parameter is: *atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags> *DefaultsdependonTTorFalcon,determinedatruntime. *Negativevaluesmeandon'tchange.
*/ int ints[8];
get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] < 1) {
printk("atari_scsi_setup: no arguments!\n"); return0;
} if (ints[0] >= 1)
setup_can_queue = ints[1]; if (ints[0] >= 2)
setup_cmd_per_lun = ints[2]; if (ints[0] >= 3)
setup_sg_tablesize = ints[3]; if (ints[0] >= 4)
setup_hostid = ints[4]; /* ints[5] (use_tagged_queuing) is ignored */ /* ints[6] (use_pdma) is ignored */ if (ints[0] >= 7)
setup_toshiba_delay = ints[7];
dprintk(NDEBUG_DMA, "scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, dir = %d\n",
hostdata->host->host_no, data, addr, count, dir);
if (!IS_A_TT() && !STRAM_ADDR(addr)) { /* If we have a non-DMAable address on a Falcon, use the dribble *buffer;'orig_addr'!=0inthereadcasetellstheinterrupt *handlertocopydatafromthedribblebuffertotheoriginally *wantedaddress.
*/ if (dir)
memcpy(atari_dma_buffer, data, count); else
atari_dma_orig_addr = data;
addr = atari_dma_phys_buffer;
}
atari_dma_startaddr = addr; /* Needed for calculating residual later. */
/* Cache cleanup stuff: On writes, push any dirty cache out before sending *ittotheperipheral.(MustbedonebeforeDMAsetup,sinceatleast *theST-DMAbeginstofillinternalbuffersrightaftersetup.For *reads,invalidateanycache,maybealteredafterDMAwithoutCPU *knowledge. * *++roman:FortheMedusa,there'snoneedatallforthatcachestuff, *becausethehardwaredoesbussnooping(fine!).
*/
dma_cache_maintenance(addr, count, dir);
/* toggle direction bit to clear FIFO and set DMA direction */
dir <<= 8;
st_dma.dma_mode_status = 0x90 | dir;
st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
st_dma.dma_mode_status = 0x90 | dir;
udelay(40); /* On writes, round up the transfer length to the next multiple of 512
* (see also comment at atari_dma_xfer_len()). */
st_dma.fdc_acces_seccount = (count + (dir ? 511 : 0)) >> 9;
udelay(40);
st_dma.dma_mode_status = 0x10 | dir;
udelay(40); /* need not restore value of dir, only boolean value is tested */
atari_dma_active = 1;
}
if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
opcode == READ_BUFFER) return CMD_SURELY_BYTE_MODE; elseif (opcode == READ_6 || opcode == READ_10 ||
opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
opcode == RECOVER_BUFFERED_DATA) { /* In case of a sequential-access target (tape), special care is *neededhere:Thetransferisblock-modeonlyifthe'fixed'bitis
* set! */ if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) return CMD_SURELY_BYTE_MODE; else return CMD_SURELY_BLOCK_MODE;
} else return CMD_MODE_UNKNOWN;
}
/* This function calculates the number of bytes that can be transferred via *DMA.OntheTT,thisisarbitrary,butontheFalconwehavetousethe *ST-DMAchip.Thereareonlymultiplesof512bytespossibleandmax. *255*512bytes:-(Thismeansalso,thatdefiningREAD_OVERRUNSisnot *possibleontheFalcon,sincethatwouldrequiretoprogramtheDMAfor *n*512-atari_read_overrunbytes.ButitseemsthattheFalcondoesn'thave *theoverrunproblem,sothisquestionisacademic:-)
*/
staticint atari_scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, struct scsi_cmnd *cmd)
{ int wanted_len = NCR5380_to_ncmd(cmd)->this_residual; int possible_len, limit;
if (wanted_len < DMA_MIN_SIZE) return0;
if (IS_A_TT()) /* TT SCSI DMA can transfer arbitrary #bytes */ return wanted_len;
/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. *255*512bytes,butthisshouldbeenough) * *++roman:Aaargl!AnotherFalcon-SCSIproblem...Therearesomecommands *thatreturnanumberofbyteswhichcannotbeknownbeforehand.Inthis *case,thegiventransferlengthisan"allocationlength".Nowit *canhappenthatthisallocationlengthisamultipleof512bytesand *theDMAisused.Butifnotn*512bytesreallyarrive,someinputdata *willbelostintheST-DMA'sFIFO:-(Thus,wehavetodistinguish *betweencommandsthatdoblocktransfersandthosethatdobyte *transfers.Butthisisn'teasy...therearelotsofvendorspecific *commands,andtheusercanissueanycommandviathe *SCSI_IOCTL_SEND_COMMAND. * *Thesolution:WeclassifySCSIcommandsin1)surelyblock-modecmd.s, *2)surelybyte-modecmd.sand3)cmd.swithunknownmode.Incase1) *and3),thethingtodoisobvious:allowanynumberofblocksviaDMA *ornone.Incase2),weapplysomeheuristic:Bytemodeisassumedif *thetransfer(allocation)lengthis<1024,hopingthatnocmd.not *explicitlyknownasbytemodehavesuchbigallocationlengths... *BTW,allthediscussionaboveappliesonlytoreads.DMAwritesare *unproblematicanyways,sincethetargetsabortsthetransferafter *receivingasufficientnumberofbytes. * *Anotherpoint:Ifthetransferisfrom/toannon-ST-RAMaddress,we *usethedribblebufferandthuscandoonlySTRAM_BUFFER_SIZEbytes.
*/
if (cmd->sc_data_direction == DMA_TO_DEVICE) { /* Write operation can always use the DMA, but the transfer size must *beroundeduptothenextmultipleof512(atari_dma_setup()does *this).
*/
possible_len = wanted_len;
} else { /* Read operations: if the wanted transfer length is not a multiple of *512,wecannotuseDMA,sincetheST-DMAcannotsplittransfers *(nointerruptonDMAfinished!)
*/ if (wanted_len & 0x1ff)
possible_len = 0; else { /* Now classify the command (see above) and decide whether it is
* allowed to do DMA at all */ switch (falcon_classify_cmd(cmd)) { case CMD_SURELY_BLOCK_MODE:
possible_len = wanted_len; break; case CMD_SURELY_BYTE_MODE:
possible_len = 0; /* DMA prohibited */ break; case CMD_MODE_UNKNOWN: default: /* For unknown commands assume block transfers if the transfer
* size/allocation length is >= 1024 */
possible_len = (wanted_len < 1024) ? 0 : wanted_len; break;
}
}
}
/* Last step: apply the hard limit on DMA transfers */
limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(NCR5380_to_ncmd(cmd)->ptr))) ?
STRAM_BUFFER_SIZE : 255*512; if (possible_len > limit)
possible_len = limit;
if (possible_len != wanted_len)
dprintk(NDEBUG_DMA, "DMA transfer now %d bytes instead of %d\n",
possible_len, wanted_len);
staticint atari_scsi_host_reset(struct scsi_cmnd *cmd)
{ int rv; unsignedlong flags;
local_irq_save(flags);
/* Abort a maybe active DMA transfer */ if (IS_A_TT()) {
tt_scsi_dma.dma_ctrl = 0;
} else { if (stdma_is_locked_by(scsi_falcon_intr))
st_dma.dma_mode_status = 0x90;
atari_dma_active = 0;
atari_dma_orig_addr = NULL;
}
rv = NCR5380_host_reset(cmd);
/* The 5380 raises its IRQ line while _RST is active but the ST DMA *"lock"hasbeenreleasedsothisinterruptmayenduphandledby *floppyorIDEdriver(ifoneofthemholdsthelock).TheNCR5380 *interruptflaghasbeenclearedalready.
*/
if (setup_can_queue > 0)
atari_scsi_template.can_queue = setup_can_queue;
if (setup_cmd_per_lun > 0)
atari_scsi_template.cmd_per_lun = setup_cmd_per_lun;
/* Don't increase sg_tablesize on Falcon! */ if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize > 0)
atari_scsi_template.sg_tablesize = setup_sg_tablesize;
if (setup_hostid >= 0) {
atari_scsi_template.this_id = setup_hostid & 7;
} elseif (IS_REACHABLE(CONFIG_NVRAM)) { /* Test if a host id is set in the NVRam */ if (ATARIHW_PRESENT(TT_CLK)) { unsignedchar b;
loff_t offset = 16;
ssize_t count = nvram_read(&b, 1, &offset);
/* If running on a Falcon and if there's TT-Ram (i.e., more than one *memoryblock,sincethere'salwaysST-RaminaFalcon),then *allocateaSTRAM_BUFFER_SIZEbytedribblebufferfortransfers *from/toalternativeRam.
*/ if (ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(EXTD_DMA) &&
m68k_realnum_memory > 1) {
atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); if (!atari_dma_buffer) {
pr_err(PFX "can't allocate ST-RAM double buffer\n"); return -ENOMEM;
}
atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
atari_dma_orig_addr = NULL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.