12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411 |
- #ifndef NCR5380_io_delay
- #define NCR5380_io_delay(x)
- #endif
- #ifndef NCR5380_acquire_dma_irq
- #define NCR5380_acquire_dma_irq(x) (1)
- #endif
- #ifndef NCR5380_release_dma_irq
- #define NCR5380_release_dma_irq(x)
- #endif
- static unsigned int disconnect_mask = ~0;
- module_param(disconnect_mask, int, 0444);
- static int do_abort(struct Scsi_Host *, unsigned int);
- static void do_reset(struct Scsi_Host *);
- static void bus_reset_cleanup(struct Scsi_Host *);
- static inline void initialize_SCp(struct scsi_cmnd *cmd)
- {
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd);
- if (scsi_bufflen(cmd)) {
- ncmd->buffer = scsi_sglist(cmd);
- ncmd->ptr = sg_virt(ncmd->buffer);
- ncmd->this_residual = ncmd->buffer->length;
- } else {
- ncmd->buffer = NULL;
- ncmd->ptr = NULL;
- ncmd->this_residual = 0;
- }
- ncmd->status = 0;
- ncmd->message = 0;
- }
- static inline void advance_sg_buffer(struct NCR5380_cmd *ncmd)
- {
- struct scatterlist *s = ncmd->buffer;
- if (!ncmd->this_residual && s && !sg_is_last(s)) {
- ncmd->buffer = sg_next(s);
- ncmd->ptr = sg_virt(ncmd->buffer);
- ncmd->this_residual = ncmd->buffer->length;
- }
- }
- static inline void set_resid_from_SCp(struct scsi_cmnd *cmd)
- {
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd);
- int resid = ncmd->this_residual;
- struct scatterlist *s = ncmd->buffer;
- if (s)
- while (!sg_is_last(s)) {
- s = sg_next(s);
- resid += s->length;
- }
- scsi_set_resid(cmd, resid);
- }
- static int NCR5380_poll_politely2(struct NCR5380_hostdata *hostdata,
- unsigned int reg1, u8 bit1, u8 val1,
- unsigned int reg2, u8 bit2, u8 val2,
- unsigned long wait)
- {
- unsigned long n = hostdata->poll_loops;
- unsigned long deadline = jiffies + wait;
- do {
- if ((NCR5380_read(reg1) & bit1) == val1)
- return 0;
- if ((NCR5380_read(reg2) & bit2) == val2)
- return 0;
- cpu_relax();
- } while (n--);
- if (!wait)
- return -ETIMEDOUT;
-
- while (time_is_after_jiffies(deadline)) {
- schedule_timeout_uninterruptible(1);
- if ((NCR5380_read(reg1) & bit1) == val1)
- return 0;
- if ((NCR5380_read(reg2) & bit2) == val2)
- return 0;
- }
- return -ETIMEDOUT;
- }
- #if NDEBUG
- static struct {
- unsigned char mask;
- const char *name;
- } signals[] = {
- {SR_DBP, "PARITY"},
- {SR_RST, "RST"},
- {SR_BSY, "BSY"},
- {SR_REQ, "REQ"},
- {SR_MSG, "MSG"},
- {SR_CD, "CD"},
- {SR_IO, "IO"},
- {SR_SEL, "SEL"},
- {0, NULL}
- },
- basrs[] = {
- {BASR_END_DMA_TRANSFER, "END OF DMA"},
- {BASR_DRQ, "DRQ"},
- {BASR_PARITY_ERROR, "PARITY ERROR"},
- {BASR_IRQ, "IRQ"},
- {BASR_PHASE_MATCH, "PHASE MATCH"},
- {BASR_BUSY_ERROR, "BUSY ERROR"},
- {BASR_ATN, "ATN"},
- {BASR_ACK, "ACK"},
- {0, NULL}
- },
- icrs[] = {
- {ICR_ASSERT_RST, "ASSERT RST"},
- {ICR_ARBITRATION_PROGRESS, "ARB. IN PROGRESS"},
- {ICR_ARBITRATION_LOST, "LOST ARB."},
- {ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"},
- {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"},
- {ICR_ASSERT_DATA, "ASSERT DATA"},
- {0, NULL}
- },
- mrs[] = {
- {MR_BLOCK_DMA_MODE, "BLOCK DMA MODE"},
- {MR_TARGET, "TARGET"},
- {MR_ENABLE_PAR_CHECK, "PARITY CHECK"},
- {MR_ENABLE_PAR_INTR, "PARITY INTR"},
- {MR_ENABLE_EOP_INTR, "EOP INTR"},
- {MR_MONITOR_BSY, "MONITOR BSY"},
- {MR_DMA_MODE, "DMA MODE"},
- {MR_ARBITRATE, "ARBITRATE"},
- {0, NULL}
- };
- static void NCR5380_print(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char status, basr, mr, icr, i;
- status = NCR5380_read(STATUS_REG);
- mr = NCR5380_read(MODE_REG);
- icr = NCR5380_read(INITIATOR_COMMAND_REG);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- printk(KERN_DEBUG "SR = 0x%02x : ", status);
- for (i = 0; signals[i].mask; ++i)
- if (status & signals[i].mask)
- printk(KERN_CONT "%s, ", signals[i].name);
- printk(KERN_CONT "\nBASR = 0x%02x : ", basr);
- for (i = 0; basrs[i].mask; ++i)
- if (basr & basrs[i].mask)
- printk(KERN_CONT "%s, ", basrs[i].name);
- printk(KERN_CONT "\nICR = 0x%02x : ", icr);
- for (i = 0; icrs[i].mask; ++i)
- if (icr & icrs[i].mask)
- printk(KERN_CONT "%s, ", icrs[i].name);
- printk(KERN_CONT "\nMR = 0x%02x : ", mr);
- for (i = 0; mrs[i].mask; ++i)
- if (mr & mrs[i].mask)
- printk(KERN_CONT "%s, ", mrs[i].name);
- printk(KERN_CONT "\n");
- }
- static struct {
- unsigned char value;
- const char *name;
- } phases[] = {
- {PHASE_DATAOUT, "DATAOUT"},
- {PHASE_DATAIN, "DATAIN"},
- {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"},
- {PHASE_MSGOUT, "MSGOUT"},
- {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}
- };
- static void NCR5380_print_phase(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char status;
- int i;
- status = NCR5380_read(STATUS_REG);
- if (!(status & SR_REQ))
- shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
- else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
- (phases[i].value != (status & PHASE_MASK)); ++i)
- ;
- shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
- }
- }
- #endif
- static const char *NCR5380_info(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- return hostdata->info;
- }
- static int NCR5380_init(struct Scsi_Host *instance, int flags)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- int i;
- unsigned long deadline;
- unsigned long accesses_per_ms;
- instance->max_lun = 7;
- hostdata->host = instance;
- hostdata->id_mask = 1 << instance->this_id;
- hostdata->id_higher_mask = 0;
- for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
- if (i > hostdata->id_mask)
- hostdata->id_higher_mask |= i;
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
- hostdata->dma_len = 0;
- spin_lock_init(&hostdata->lock);
- hostdata->connected = NULL;
- hostdata->sensing = NULL;
- INIT_LIST_HEAD(&hostdata->autosense);
- INIT_LIST_HEAD(&hostdata->unissued);
- INIT_LIST_HEAD(&hostdata->disconnected);
- hostdata->flags = flags;
- INIT_WORK(&hostdata->main_task, NCR5380_main);
- hostdata->work_q = alloc_workqueue("ncr5380_%d",
- WQ_UNBOUND | WQ_MEM_RECLAIM,
- 1, instance->host_no);
- if (!hostdata->work_q)
- return -ENOMEM;
- snprintf(hostdata->info, sizeof(hostdata->info),
- "%s, irq %d, io_port 0x%lx, base 0x%lx, can_queue %d, cmd_per_lun %d, sg_tablesize %d, this_id %d, flags { %s%s%s}",
- instance->hostt->name, instance->irq, hostdata->io_port,
- hostdata->base, instance->can_queue, instance->cmd_per_lun,
- instance->sg_tablesize, instance->this_id,
- hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "",
- hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
- hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "");
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- i = 0;
- deadline = jiffies + 1;
- do {
- cpu_relax();
- } while (time_is_after_jiffies(deadline));
- deadline += msecs_to_jiffies(256);
- do {
- NCR5380_read(STATUS_REG);
- ++i;
- cpu_relax();
- } while (time_is_after_jiffies(deadline));
- accesses_per_ms = i / 256;
- hostdata->poll_loops = NCR5380_REG_POLL_TIME * accesses_per_ms / 2;
- return 0;
- }
- static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- int pass;
- for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
- switch (pass) {
- case 1:
- case 3:
- case 5:
- shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
- NCR5380_poll_politely(hostdata,
- STATUS_REG, SR_BSY, 0, 5 * HZ);
- break;
- case 2:
- shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
- do_abort(instance, 1);
- break;
- case 4:
- shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
- do_reset(instance);
-
- if (hostdata->flags & FLAG_TOSHIBA_DELAY)
- msleep(2500);
- else
- msleep(500);
- break;
- case 6:
- shost_printk(KERN_ERR, instance, "bus locked solid\n");
- return -ENXIO;
- }
- }
- return 0;
- }
- static void NCR5380_exit(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- cancel_work_sync(&hostdata->main_task);
- destroy_workqueue(hostdata->work_q);
- }
- static void complete_cmd(struct Scsi_Host *instance,
- struct scsi_cmnd *cmd)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
- if (hostdata->sensing == cmd) {
-
- if (get_status_byte(cmd) != SAM_STAT_GOOD) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- } else {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
- }
- hostdata->sensing = NULL;
- }
- scsi_done(cmd);
- }
- static int NCR5380_queue_command(struct Scsi_Host *instance,
- struct scsi_cmnd *cmd)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd);
- unsigned long flags;
- #if (NDEBUG & NDEBUG_NO_WRITE)
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
- cmd->result = (DID_ERROR << 16);
- scsi_done(cmd);
- return 0;
- }
- #endif
- cmd->result = 0;
- spin_lock_irqsave(&hostdata->lock, flags);
- if (!NCR5380_acquire_dma_irq(instance)) {
- spin_unlock_irqrestore(&hostdata->lock, flags);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- if (cmd->cmnd[0] == REQUEST_SENSE)
- list_add(&ncmd->list, &hostdata->unissued);
- else
- list_add_tail(&ncmd->list, &hostdata->unissued);
- spin_unlock_irqrestore(&hostdata->lock, flags);
- dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
- cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-
- queue_work(hostdata->work_q, &hostdata->main_task);
- return 0;
- }
- static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
-
- if (list_empty(&hostdata->disconnected) &&
- list_empty(&hostdata->unissued) &&
- list_empty(&hostdata->autosense) &&
- !hostdata->connected &&
- !hostdata->selecting) {
- NCR5380_release_dma_irq(instance);
- }
- }
- static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct NCR5380_cmd *ncmd;
- struct scsi_cmnd *cmd;
- if (hostdata->sensing || list_empty(&hostdata->autosense)) {
- list_for_each_entry(ncmd, &hostdata->unissued, list) {
- cmd = NCR5380_to_scmd(ncmd);
- dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
- cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
- if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) {
- list_del(&ncmd->list);
- dsprintk(NDEBUG_QUEUES, instance,
- "dequeue: removed %p from issue queue\n", cmd);
- return cmd;
- }
- }
- } else {
-
- ncmd = list_first_entry(&hostdata->autosense,
- struct NCR5380_cmd, list);
- list_del(&ncmd->list);
- cmd = NCR5380_to_scmd(ncmd);
- dsprintk(NDEBUG_QUEUES, instance,
- "dequeue: removed %p from autosense queue\n", cmd);
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
- hostdata->sensing = cmd;
- return cmd;
- }
- return NULL;
- }
- static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd);
- if (hostdata->sensing == cmd) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- list_add(&ncmd->list, &hostdata->autosense);
- hostdata->sensing = NULL;
- } else
- list_add(&ncmd->list, &hostdata->unissued);
- }
- static void NCR5380_main(struct work_struct *work)
- {
- struct NCR5380_hostdata *hostdata =
- container_of(work, struct NCR5380_hostdata, main_task);
- struct Scsi_Host *instance = hostdata->host;
- int done;
- do {
- done = 1;
- spin_lock_irq(&hostdata->lock);
- while (!hostdata->connected && !hostdata->selecting) {
- struct scsi_cmnd *cmd = dequeue_next_cmd(instance);
- if (!cmd)
- break;
- dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
-
-
- if (!NCR5380_select(instance, cmd)) {
- dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
- } else {
- dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
- "main: select failed, returning %p to queue\n", cmd);
- requeue_cmd(instance, cmd);
- }
- }
- if (hostdata->connected && !hostdata->dma_len) {
- dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
- NCR5380_information_transfer(instance);
- done = 0;
- }
- if (!hostdata->connected) {
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- maybe_release_dma_irq(instance);
- }
- spin_unlock_irq(&hostdata->lock);
- if (!done)
- cond_resched();
- } while (!done);
- }
- static void NCR5380_dma_complete(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(hostdata->connected);
- int transferred;
- unsigned char **data;
- int *count;
- int saved_data = 0, overrun = 0;
- unsigned char p;
- if (hostdata->read_overruns) {
- p = ncmd->phase;
- if (p & SR_IO) {
- udelay(10);
- if ((NCR5380_read(BUS_AND_STATUS_REG) &
- (BASR_PHASE_MATCH | BASR_ACK)) ==
- (BASR_PHASE_MATCH | BASR_ACK)) {
- saved_data = NCR5380_read(INPUT_DATA_REG);
- overrun = 1;
- dsprintk(NDEBUG_DMA, instance, "read overrun handled\n");
- }
- }
- }
- #ifdef CONFIG_SUN3
- if (sun3scsi_dma_finish(hostdata->connected->sc_data_direction)) {
- pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n",
- instance->host_no);
- BUG();
- }
- if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
- (BASR_PHASE_MATCH | BASR_ACK)) {
- pr_err("scsi%d: BASR %02x\n", instance->host_no,
- NCR5380_read(BUS_AND_STATUS_REG));
- pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n",
- instance->host_no);
- BUG();
- }
- #endif
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- transferred = hostdata->dma_len - NCR5380_dma_residual(hostdata);
- hostdata->dma_len = 0;
- data = (unsigned char **)&ncmd->ptr;
- count = &ncmd->this_residual;
- *data += transferred;
- *count -= transferred;
- if (hostdata->read_overruns) {
- int cnt, toPIO;
- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
- cnt = toPIO = hostdata->read_overruns;
- if (overrun) {
- dsprintk(NDEBUG_DMA, instance,
- "Got an input overrun, using saved byte\n");
- *(*data)++ = saved_data;
- (*count)--;
- cnt--;
- toPIO--;
- }
- if (toPIO > 0) {
- dsprintk(NDEBUG_DMA, instance,
- "Doing %d byte PIO to 0x%p\n", cnt, *data);
- NCR5380_transfer_pio(instance, &p, &cnt, data, 0);
- *count -= toPIO - cnt;
- }
- }
- }
- }
- static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id)
- {
- struct Scsi_Host *instance = dev_id;
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- int handled = 0;
- unsigned char basr;
- unsigned long flags;
- spin_lock_irqsave(&hostdata->lock, flags);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- if (basr & BASR_IRQ) {
- unsigned char mr = NCR5380_read(MODE_REG);
- unsigned char sr = NCR5380_read(STATUS_REG);
- dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
- irq, basr, sr, mr);
- if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
-
- dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
- if (hostdata->connected) {
- NCR5380_dma_complete(instance);
- queue_work(hostdata->work_q, &hostdata->main_task);
- } else {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- } else if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
- (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
-
- NCR5380_write(SELECT_ENABLE_REG, 0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
- if (!hostdata->connected) {
- NCR5380_reselect(instance);
- queue_work(hostdata->work_q, &hostdata->main_task);
- }
- if (!hostdata->connected)
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- } else {
-
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- if (sr & SR_RST) {
-
- shost_printk(KERN_WARNING, instance,
- "bus reset interrupt\n");
- bus_reset_cleanup(instance);
- } else {
- dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
- }
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
- #endif
- }
- handled = 1;
- } else {
- dsprintk(NDEBUG_INTR, instance, "interrupt without IRQ bit\n");
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
- #endif
- }
- spin_unlock_irqrestore(&hostdata->lock, flags);
- return IRQ_RETVAL(handled);
- }
- static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
- __releases(&hostdata->lock) __acquires(&hostdata->lock)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char tmp[3], phase;
- unsigned char *data;
- int len;
- int err;
- bool ret = true;
- bool can_disconnect = instance->irq != NO_IRQ &&
- cmd->cmnd[0] != REQUEST_SENSE &&
- (disconnect_mask & BIT(scmd_id(cmd)));
- NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
- instance->this_id);
-
- hostdata->selecting = cmd;
-
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
- NCR5380_write(MODE_REG, MR_ARBITRATE);
-
- spin_unlock_irq(&hostdata->lock);
- err = NCR5380_poll_politely2(hostdata, MODE_REG, MR_ARBITRATE, 0,
- INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
- ICR_ARBITRATION_PROGRESS, HZ);
- spin_lock_irq(&hostdata->lock);
- if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
-
- goto out;
- }
- if (!hostdata->selecting) {
-
- NCR5380_write(MODE_REG, MR_BASE);
- return false;
- }
- if (err < 0) {
- NCR5380_write(MODE_REG, MR_BASE);
- shost_printk(KERN_ERR, instance,
- "select: arbitration timeout\n");
- goto out;
- }
- spin_unlock_irq(&hostdata->lock);
-
- udelay(3);
-
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
- NCR5380_write(MODE_REG, MR_BASE);
- dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
- spin_lock_irq(&hostdata->lock);
- goto out;
- }
-
- NCR5380_write(INITIATOR_COMMAND_REG,
- ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
-
- if (hostdata->flags & FLAG_TOSHIBA_DELAY)
- udelay(15);
- else
- udelay(2);
- spin_lock_irq(&hostdata->lock);
-
- if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
- goto out;
- if (!hostdata->selecting) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return false;
- }
- dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
-
- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
- NCR5380_write(MODE_REG, MR_BASE);
-
- NCR5380_write(SELECT_ENABLE_REG, 0);
- spin_unlock_irq(&hostdata->lock);
-
- udelay(1);
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL);
-
- udelay(1);
- dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
-
- err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_BSY, SR_BSY,
- msecs_to_jiffies(250));
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
- spin_lock_irq(&hostdata->lock);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_reselect(instance);
- shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
- goto out;
- }
- if (err < 0) {
- spin_lock_irq(&hostdata->lock);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- if (!hostdata->selecting)
- return false;
- cmd->result = DID_BAD_TARGET << 16;
- complete_cmd(instance, cmd);
- dsprintk(NDEBUG_SELECTION, instance,
- "target did not respond within 250ms\n");
- ret = false;
- goto out;
- }
-
- udelay(1);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
-
- err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ);
- spin_lock_irq(&hostdata->lock);
- if (err < 0) {
- shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- goto out;
- }
- if (!hostdata->selecting) {
- do_abort(instance, 0);
- return false;
- }
- dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
- scmd_id(cmd));
- tmp[0] = IDENTIFY(can_disconnect, cmd->device->lun);
- len = 1;
- data = tmp;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- if (len) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- cmd->result = DID_ERROR << 16;
- complete_cmd(instance, cmd);
- dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n");
- ret = false;
- goto out;
- }
- dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
- hostdata->connected = cmd;
- hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
- #endif
- initialize_SCp(cmd);
- ret = false;
- out:
- if (!hostdata->selecting)
- return false;
- hostdata->selecting = NULL;
- return ret;
- }
- static int NCR5380_transfer_pio(struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data, unsigned int can_sleep)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char p = *phase, tmp;
- int c = *count;
- unsigned char *d = *data;
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- do {
-
- if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- HZ * can_sleep) < 0)
- break;
- dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
-
- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
- dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
- NCR5380_dprint_phase(NDEBUG_PIO, instance);
- break;
- }
-
- if (!(p & SR_IO))
- NCR5380_write(OUTPUT_DATA_REG, *d);
- else
- *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
- ++d;
-
- if (!(p & SR_IO)) {
- if (!((p & SR_MSG) && c > 1)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
- } else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- }
- } else {
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- }
- if (NCR5380_poll_politely(hostdata,
- STATUS_REG, SR_REQ, 0, 5 * HZ * can_sleep) < 0)
- break;
- dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
- if (!(p == PHASE_MSGIN && c == 1)) {
- if (p == PHASE_MSGOUT && c > 1)
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- else
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
- } while (--c);
- dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
- *count = c;
- *data = d;
- tmp = NCR5380_read(STATUS_REG);
-
- if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
- *phase = tmp & PHASE_MASK;
- else
- *phase = PHASE_UNKNOWN;
- if (!c || (*phase == p))
- return 0;
- else
- return -1;
- }
- static void do_reset(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata __maybe_unused *hostdata = shost_priv(instance);
- unsigned long flags;
- local_irq_save(flags);
- NCR5380_write(TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- udelay(50);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- local_irq_restore(flags);
- }
- static int do_abort(struct Scsi_Host *instance, unsigned int can_sleep)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char *msgptr, phase, tmp;
- int len;
- int rc;
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
- rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- 10 * HZ * can_sleep);
- if (rc < 0)
- goto out;
- tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- if (tmp != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG,
- ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0,
- 3 * HZ * can_sleep);
- if (rc < 0)
- goto out;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- }
- tmp = ABORT;
- msgptr = &tmp;
- len = 1;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(instance, &phase, &len, &msgptr, can_sleep);
- if (len)
- rc = -ENXIO;
-
- out:
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return rc;
- }
- static int NCR5380_transfer_dma(struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- int c = *count;
- unsigned char p = *phase;
- unsigned char *d = *data;
- unsigned char tmp;
- int result = 0;
- if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
- *phase = tmp;
- return -1;
- }
- NCR5380_to_ncmd(hostdata->connected)->phase = p;
- if (p & SR_IO) {
- if (hostdata->read_overruns)
- c -= hostdata->read_overruns;
- else if (hostdata->flags & FLAG_DMA_FIXUP)
- --c;
- }
- dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
- (p & SR_IO) ? "receive" : "send", c, d);
- #ifdef CONFIG_SUN3
-
- sun3scsi_dma_start(c, *data);
- #endif
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
- MR_ENABLE_EOP_INTR);
- if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
-
- if (p & SR_IO)
- result = NCR5380_dma_recv_setup(hostdata, d, c);
- else
- result = NCR5380_dma_send_setup(hostdata, d, c);
- }
-
- if (p & SR_IO) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_io_delay(1);
- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
- } else {
- NCR5380_io_delay(1);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
- NCR5380_io_delay(1);
- NCR5380_write(START_DMA_SEND_REG, 0);
- NCR5380_io_delay(1);
- }
- #ifdef CONFIG_SUN3
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
- #endif
- sun3_dma_active = 1;
- #endif
- if (hostdata->flags & FLAG_LATE_DMA_SETUP) {
-
- if (p & SR_IO)
- result = NCR5380_dma_recv_setup(hostdata, d, c);
- else
- result = NCR5380_dma_send_setup(hostdata, d, c);
- }
-
- if (result < 0)
- return result;
-
- if (result > 0) {
- hostdata->dma_len = result;
- return 0;
- }
-
- hostdata->dma_len = c;
- if (hostdata->flags & FLAG_DMA_FIXUP) {
- if (p & SR_IO) {
-
- if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
- BASR_DRQ, BASR_DRQ, 0) < 0) {
- result = -1;
- shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
- }
- if (NCR5380_poll_politely(hostdata, STATUS_REG,
- SR_REQ, 0, 0) < 0) {
- result = -1;
- shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
- }
- d[*count - 1] = NCR5380_read(INPUT_DATA_REG);
- } else {
-
- if (NCR5380_poll_politely2(hostdata,
- BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
- BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0) < 0) {
- result = -1;
- shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
- }
- }
- }
- NCR5380_dma_complete(instance);
- return result;
- }
- static void NCR5380_information_transfer(struct Scsi_Host *instance)
- __releases(&hostdata->lock) __acquires(&hostdata->lock)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char msgout = NOP;
- int sink = 0;
- int len;
- int transfersize;
- unsigned char *data;
- unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- struct scsi_cmnd *cmd;
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
- #endif
- while ((cmd = hostdata->connected)) {
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd);
- tmp = NCR5380_read(STATUS_REG);
-
- if (tmp & SR_REQ) {
- phase = (tmp & PHASE_MASK);
- if (phase != old_phase) {
- old_phase = phase;
- NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
- }
- #ifdef CONFIG_SUN3
- if (phase == PHASE_CMDOUT &&
- sun3_dma_setup_done != cmd) {
- int count;
- advance_sg_buffer(ncmd);
- count = sun3scsi_dma_xfer_len(hostdata, cmd);
- if (count > 0) {
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- sun3scsi_dma_send_setup(hostdata,
- ncmd->ptr, count);
- else
- sun3scsi_dma_recv_setup(hostdata,
- ncmd->ptr, count);
- sun3_dma_setup_done = cmd;
- }
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
- #endif
- }
- #endif
- if (sink && (phase != PHASE_MSGOUT)) {
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ)
- ;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 0;
- continue;
- }
- switch (phase) {
- case PHASE_DATAOUT:
- #if (NDEBUG & NDEBUG_NO_DATAOUT)
- shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
- sink = 1;
- do_abort(instance, 0);
- cmd->result = DID_ERROR << 16;
- complete_cmd(instance, cmd);
- hostdata->connected = NULL;
- hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
- return;
- #endif
- case PHASE_DATAIN:
-
- advance_sg_buffer(ncmd);
- dsprintk(NDEBUG_INFORMATION, instance,
- "this residual %d, sg ents %d\n",
- ncmd->this_residual,
- sg_nents(ncmd->buffer));
-
- transfersize = 0;
- if (!cmd->device->borken)
- transfersize = NCR5380_dma_xfer_len(hostdata, cmd);
- if (transfersize > 0) {
- len = transfersize;
- if (NCR5380_transfer_dma(instance, &phase,
- &len, (unsigned char **)&ncmd->ptr)) {
-
- scmd_printk(KERN_INFO, cmd,
- "switching to slow handshake\n");
- cmd->device->borken = 1;
- do_reset(instance);
- bus_reset_cleanup(instance);
- }
- } else {
-
- transfersize = min(ncmd->this_residual,
- NCR5380_PIO_CHUNK_SIZE);
- len = transfersize;
- NCR5380_transfer_pio(instance, &phase, &len,
- (unsigned char **)&ncmd->ptr,
- 0);
- ncmd->this_residual -= transfersize - len;
- }
- #ifdef CONFIG_SUN3
- if (sun3_dma_setup_done == cmd)
- sun3_dma_setup_done = NULL;
- #endif
- return;
- case PHASE_MSGIN:
- len = 1;
- data = &tmp;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- ncmd->message = tmp;
- switch (tmp) {
- case ABORT:
- set_host_byte(cmd, DID_ABORT);
- fallthrough;
- case COMMAND_COMPLETE:
-
- sink = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dsprintk(NDEBUG_QUEUES, instance,
- "COMMAND COMPLETE %p target %d lun %llu\n",
- cmd, scmd_id(cmd), cmd->device->lun);
- hostdata->connected = NULL;
- hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
- set_status_byte(cmd, ncmd->status);
- set_resid_from_SCp(cmd);
- if (cmd->cmnd[0] == REQUEST_SENSE)
- complete_cmd(instance, cmd);
- else {
- if (ncmd->status == SAM_STAT_CHECK_CONDITION ||
- ncmd->status == SAM_STAT_COMMAND_TERMINATED) {
- dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
- cmd);
- list_add_tail(&ncmd->list,
- &hostdata->autosense);
- } else
- complete_cmd(instance, cmd);
- }
-
- NCR5380_write(TARGET_COMMAND_REG, 0);
- return;
- case MESSAGE_REJECT:
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- switch (hostdata->last_message) {
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- case SIMPLE_QUEUE_TAG:
- cmd->device->simple_tags = 0;
- hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
- break;
- default:
- break;
- }
- break;
- case DISCONNECT:
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = NULL;
- list_add(&ncmd->list, &hostdata->disconnected);
- dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
- instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
- cmd, scmd_id(cmd), cmd->device->lun);
-
- NCR5380_write(TARGET_COMMAND_REG, 0);
- #ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
- #endif
- return;
-
- case SAVE_POINTERS:
- case RESTORE_POINTERS:
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- break;
- case EXTENDED_MESSAGE:
-
- extended_msg[0] = EXTENDED_MESSAGE;
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- spin_unlock_irq(&hostdata->lock);
- dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
- len = 2;
- data = extended_msg + 1;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 1);
- dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
- (int)extended_msg[1],
- (int)extended_msg[2]);
- if (!len && extended_msg[1] > 0 &&
- extended_msg[1] <= sizeof(extended_msg) - 2) {
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- len = extended_msg[1] - 1;
- data = extended_msg + 3;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 1);
- dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
- len);
- switch (extended_msg[2]) {
- case EXTENDED_SDTR:
- case EXTENDED_WDTR:
- tmp = 0;
- }
- } else if (len) {
- shost_printk(KERN_ERR, instance, "error receiving extended message\n");
- tmp = 0;
- } else {
- shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
- extended_msg[2], extended_msg[1]);
- tmp = 0;
- }
- spin_lock_irq(&hostdata->lock);
- if (!hostdata->connected)
- return;
-
- fallthrough;
- default:
-
- if (tmp == EXTENDED_MESSAGE)
- scmd_printk(KERN_INFO, cmd,
- "rejecting unknown extended message code %02x, length %d\n",
- extended_msg[2], extended_msg[1]);
- else if (tmp)
- scmd_printk(KERN_INFO, cmd,
- "rejecting unknown message code %02x\n",
- tmp);
- msgout = MESSAGE_REJECT;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- break;
- }
- break;
- case PHASE_MSGOUT:
- len = 1;
- data = &msgout;
- hostdata->last_message = msgout;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- if (msgout == ABORT) {
- hostdata->connected = NULL;
- hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
- cmd->result = DID_ERROR << 16;
- complete_cmd(instance, cmd);
- return;
- }
- msgout = NOP;
- break;
- case PHASE_CMDOUT:
- len = cmd->cmd_len;
- data = cmd->cmnd;
-
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- break;
- case PHASE_STATIN:
- len = 1;
- data = &tmp;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- ncmd->status = tmp;
- break;
- default:
- shost_printk(KERN_ERR, instance, "unknown phase\n");
- NCR5380_dprint(NDEBUG_ANY, instance);
- }
- } else {
- spin_unlock_irq(&hostdata->lock);
- NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ);
- spin_lock_irq(&hostdata->lock);
- }
- }
- }
- static void NCR5380_reselect(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char target_mask;
- unsigned char lun;
- unsigned char msg[3];
- struct NCR5380_cmd *ncmd;
- struct scsi_cmnd *tmp;
-
- NCR5380_write(MODE_REG, MR_BASE);
- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
- if (!target_mask || target_mask & (target_mask - 1)) {
- shost_printk(KERN_WARNING, instance,
- "reselect: bad target_mask 0x%02x\n", target_mask);
- return;
- }
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
- if (NCR5380_poll_politely(hostdata,
- STATUS_REG, SR_SEL, 0, 0) < 0) {
- shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n");
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return;
- }
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- if (NCR5380_poll_politely(hostdata,
- STATUS_REG, SR_REQ, SR_REQ, 0) < 0) {
- if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0)
-
- return;
- shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n");
- do_abort(instance, 0);
- return;
- }
- #ifdef CONFIG_SUN3
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
-
- msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
- #else
- {
- int len = 1;
- unsigned char *data = msg;
- unsigned char phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
- if (len) {
- do_abort(instance, 0);
- return;
- }
- }
- #endif
- if (!(msg[0] & 0x80)) {
- shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
- spi_print_msg(msg);
- printk("\n");
- do_abort(instance, 0);
- return;
- }
- lun = msg[0] & 0x07;
-
-
- tmp = NULL;
- list_for_each_entry(ncmd, &hostdata->disconnected, list) {
- struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- if (target_mask == (1 << scmd_id(cmd)) &&
- lun == (u8)cmd->device->lun) {
- list_del(&ncmd->list);
- tmp = cmd;
- break;
- }
- }
- if (tmp) {
- dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
- "reselect: removed %p from disconnected queue\n", tmp);
- } else {
- int target = ffs(target_mask) - 1;
- shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
- target_mask, lun);
-
- if (do_abort(instance, 0) == 0)
- hostdata->busy[target] &= ~(1 << lun);
- return;
- }
- #ifdef CONFIG_SUN3
- if (sun3_dma_setup_done != tmp) {
- int count;
- advance_sg_buffer(ncmd);
- count = sun3scsi_dma_xfer_len(hostdata, tmp);
- if (count > 0) {
- if (tmp->sc_data_direction == DMA_TO_DEVICE)
- sun3scsi_dma_send_setup(hostdata,
- ncmd->ptr, count);
- else
- sun3scsi_dma_recv_setup(hostdata,
- ncmd->ptr, count);
- sun3_dma_setup_done = tmp;
- }
- }
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- #endif
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = tmp;
- dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu\n",
- scmd_id(tmp), tmp->device->lun);
- }
- static bool list_find_cmd(struct list_head *haystack,
- struct scsi_cmnd *needle)
- {
- struct NCR5380_cmd *ncmd;
- list_for_each_entry(ncmd, haystack, list)
- if (NCR5380_to_scmd(ncmd) == needle)
- return true;
- return false;
- }
- static bool list_del_cmd(struct list_head *haystack,
- struct scsi_cmnd *needle)
- {
- if (list_find_cmd(haystack, needle)) {
- struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(needle);
- list_del(&ncmd->list);
- return true;
- }
- return false;
- }
- static int NCR5380_abort(struct scsi_cmnd *cmd)
- {
- struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned long flags;
- int result = SUCCESS;
- spin_lock_irqsave(&hostdata->lock, flags);
- #if (NDEBUG & NDEBUG_ANY)
- scmd_printk(KERN_INFO, cmd, __func__);
- #endif
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
- if (list_del_cmd(&hostdata->unissued, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: removed %p from issue queue\n", cmd);
- cmd->result = DID_ABORT << 16;
- scsi_done(cmd);
- goto out;
- }
- if (hostdata->selecting == cmd) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: cmd %p == selecting\n", cmd);
- hostdata->selecting = NULL;
- cmd->result = DID_ABORT << 16;
- complete_cmd(instance, cmd);
- goto out;
- }
- if (list_del_cmd(&hostdata->disconnected, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: removed %p from disconnected list\n", cmd);
-
- set_host_byte(cmd, DID_ERROR);
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
- if (hostdata->connected == cmd) {
- dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
- hostdata->connected = NULL;
- hostdata->dma_len = 0;
- if (do_abort(instance, 0) < 0) {
- set_host_byte(cmd, DID_ERROR);
- complete_cmd(instance, cmd);
- result = FAILED;
- goto out;
- }
- set_host_byte(cmd, DID_ABORT);
- complete_cmd(instance, cmd);
- goto out;
- }
- if (list_del_cmd(&hostdata->autosense, cmd)) {
- dsprintk(NDEBUG_ABORT, instance,
- "abort: removed %p from sense queue\n", cmd);
- complete_cmd(instance, cmd);
- }
- out:
- if (result == FAILED)
- dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
- else {
- hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
- dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
- }
- queue_work(hostdata->work_q, &hostdata->main_task);
- spin_unlock_irqrestore(&hostdata->lock, flags);
- return result;
- }
- static void bus_reset_cleanup(struct Scsi_Host *instance)
- {
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- int i;
- struct NCR5380_cmd *ncmd;
-
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- if (hostdata->selecting) {
- hostdata->selecting->result = DID_RESET << 16;
- complete_cmd(instance, hostdata->selecting);
- hostdata->selecting = NULL;
- }
- list_for_each_entry(ncmd, &hostdata->disconnected, list) {
- struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- set_host_byte(cmd, DID_RESET);
- complete_cmd(instance, cmd);
- }
- INIT_LIST_HEAD(&hostdata->disconnected);
- list_for_each_entry(ncmd, &hostdata->autosense, list) {
- struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- scsi_done(cmd);
- }
- INIT_LIST_HEAD(&hostdata->autosense);
- if (hostdata->connected) {
- set_host_byte(hostdata->connected, DID_RESET);
- complete_cmd(instance, hostdata->connected);
- hostdata->connected = NULL;
- }
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
- hostdata->dma_len = 0;
- queue_work(hostdata->work_q, &hostdata->main_task);
- }
- static int NCR5380_host_reset(struct scsi_cmnd *cmd)
- {
- struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned long flags;
- struct NCR5380_cmd *ncmd;
- spin_lock_irqsave(&hostdata->lock, flags);
- #if (NDEBUG & NDEBUG_ANY)
- shost_printk(KERN_INFO, instance, __func__);
- #endif
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
- list_for_each_entry(ncmd, &hostdata->unissued, list) {
- struct scsi_cmnd *scmd = NCR5380_to_scmd(ncmd);
- scmd->result = DID_RESET << 16;
- scsi_done(scmd);
- }
- INIT_LIST_HEAD(&hostdata->unissued);
- do_reset(instance);
- bus_reset_cleanup(instance);
- spin_unlock_irqrestore(&hostdata->lock, flags);
- return SUCCESS;
- }
|