1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907 |
- /*
- Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
- Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
- This program is free software; you may redistribute and/or modify it under
- the terms of the GNU General Public License Version 2 as published by the
- Free Software Foundation.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for complete details.
- The author respectfully requests that any modifications to this software be
- sent directly to him for evaluation and testing.
- Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose
- advice has been invaluable, to David Gentzel, for writing the original Linux
- BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site.
- Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB
- Manager available as freely redistributable source code.
- */
- #define blogic_drvr_version "2.1.17"
- #define blogic_drvr_date "12 September 2013"
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/types.h>
- #include <linux/blkdev.h>
- #include <linux/delay.h>
- #include <linux/ioport.h>
- #include <linux/mm.h>
- #include <linux/stat.h>
- #include <linux/pci.h>
- #include <linux/spinlock.h>
- #include <linux/jiffies.h>
- #include <linux/dma-mapping.h>
- #include <linux/slab.h>
- #include <scsi/scsicam.h>
- #include <asm/dma.h>
- #include <asm/io.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_tcq.h>
- #include "BusLogic.h"
- #include "FlashPoint.c"
- #ifndef FAILURE
- #define FAILURE (-1)
- #endif
- static struct scsi_host_template blogic_template;
- /*
- blogic_drvr_options_count is a count of the number of BusLogic Driver
- Options specifications provided via the Linux Kernel Command Line or via
- the Loadable Kernel Module Installation Facility.
- */
- static int blogic_drvr_options_count;
- /*
- blogic_drvr_options is an array of Driver Options structures representing
- BusLogic Driver Options specifications provided via the Linux Kernel Command
- Line or via the Loadable Kernel Module Installation Facility.
- */
- static struct blogic_drvr_options blogic_drvr_options[BLOGIC_MAX_ADAPTERS];
- /*
- BusLogic can be assigned a string by insmod.
- */
- MODULE_LICENSE("GPL");
- #ifdef MODULE
- static char *BusLogic;
- module_param(BusLogic, charp, 0);
- #endif
- /*
- blogic_probe_options is a set of Probe Options to be applied across
- all BusLogic Host Adapters.
- */
- static struct blogic_probe_options blogic_probe_options;
- /*
- blogic_global_options is a set of Global Options to be applied across
- all BusLogic Host Adapters.
- */
- static struct blogic_global_options blogic_global_options;
- static LIST_HEAD(blogic_host_list);
- /*
- blogic_probeinfo_count is the number of entries in blogic_probeinfo_list.
- */
- static int blogic_probeinfo_count;
- /*
- blogic_probeinfo_list is the list of I/O Addresses and Bus Probe Information
- to be checked for potential BusLogic Host Adapters. It is initialized by
- interrogating the PCI Configuration Space on PCI machines as well as from the
- list of standard BusLogic I/O Addresses.
- */
- static struct blogic_probeinfo *blogic_probeinfo_list;
- /*
- blogic_cmd_failure_reason holds a string identifying the reason why a
- call to blogic_cmd failed. It is only non-NULL when blogic_cmd
- returns a failure code.
- */
- static char *blogic_cmd_failure_reason;
- /*
- blogic_announce_drvr announces the Driver Version and Date, Author's
- Name, Copyright Notice, and Electronic Mail Address.
- */
- static void blogic_announce_drvr(struct blogic_adapter *adapter)
- {
- blogic_announce("***** BusLogic SCSI Driver Version " blogic_drvr_version " of " blogic_drvr_date " *****\n", adapter);
- blogic_announce("Copyright 1995-1998 by Leonard N. Zubkoff " "<lnz@dandelion.com>\n", adapter);
- }
- /*
- blogic_drvr_info returns the Host Adapter Name to identify this SCSI
- Driver and Host Adapter.
- */
- static const char *blogic_drvr_info(struct Scsi_Host *host)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) host->hostdata;
- return adapter->full_model;
- }
- /*
- blogic_init_ccbs initializes a group of Command Control Blocks (CCBs)
- for Host Adapter from the blk_size bytes located at blk_pointer. The newly
- created CCBs are added to Host Adapter's free list.
- */
- static void blogic_init_ccbs(struct blogic_adapter *adapter, void *blk_pointer,
- int blk_size, dma_addr_t blkp)
- {
- struct blogic_ccb *ccb = (struct blogic_ccb *) blk_pointer;
- unsigned int offset = 0;
- memset(blk_pointer, 0, blk_size);
- ccb->allocgrp_head = blkp;
- ccb->allocgrp_size = blk_size;
- while ((blk_size -= sizeof(struct blogic_ccb)) >= 0) {
- ccb->status = BLOGIC_CCB_FREE;
- ccb->adapter = adapter;
- ccb->dma_handle = (u32) blkp + offset;
- if (blogic_flashpoint_type(adapter)) {
- ccb->callback = blogic_qcompleted_ccb;
- ccb->base_addr = adapter->fpinfo.base_addr;
- }
- ccb->next = adapter->free_ccbs;
- ccb->next_all = adapter->all_ccbs;
- adapter->free_ccbs = ccb;
- adapter->all_ccbs = ccb;
- adapter->alloc_ccbs++;
- ccb++;
- offset += sizeof(struct blogic_ccb);
- }
- }
- /*
- blogic_create_initccbs allocates the initial CCBs for Host Adapter.
- */
- static bool __init blogic_create_initccbs(struct blogic_adapter *adapter)
- {
- int blk_size = BLOGIC_CCB_GRP_ALLOCSIZE * sizeof(struct blogic_ccb);
- void *blk_pointer;
- dma_addr_t blkp;
- while (adapter->alloc_ccbs < adapter->initccbs) {
- blk_pointer = pci_alloc_consistent(adapter->pci_device,
- blk_size, &blkp);
- if (blk_pointer == NULL) {
- blogic_err("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n",
- adapter);
- return false;
- }
- blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp);
- }
- return true;
- }
- /*
- blogic_destroy_ccbs deallocates the CCBs for Host Adapter.
- */
- static void blogic_destroy_ccbs(struct blogic_adapter *adapter)
- {
- struct blogic_ccb *next_ccb = adapter->all_ccbs, *ccb, *lastccb = NULL;
- adapter->all_ccbs = NULL;
- adapter->free_ccbs = NULL;
- while ((ccb = next_ccb) != NULL) {
- next_ccb = ccb->next_all;
- if (ccb->allocgrp_head) {
- if (lastccb)
- pci_free_consistent(adapter->pci_device,
- lastccb->allocgrp_size, lastccb,
- lastccb->allocgrp_head);
- lastccb = ccb;
- }
- }
- if (lastccb)
- pci_free_consistent(adapter->pci_device, lastccb->allocgrp_size,
- lastccb, lastccb->allocgrp_head);
- }
- /*
- blogic_create_addlccbs allocates Additional CCBs for Host Adapter. If
- allocation fails and there are no remaining CCBs available, the Driver Queue
- Depth is decreased to a known safe value to avoid potential deadlocks when
- multiple host adapters share the same IRQ Channel.
- */
- static void blogic_create_addlccbs(struct blogic_adapter *adapter,
- int addl_ccbs, bool print_success)
- {
- int blk_size = BLOGIC_CCB_GRP_ALLOCSIZE * sizeof(struct blogic_ccb);
- int prev_alloc = adapter->alloc_ccbs;
- void *blk_pointer;
- dma_addr_t blkp;
- if (addl_ccbs <= 0)
- return;
- while (adapter->alloc_ccbs - prev_alloc < addl_ccbs) {
- blk_pointer = pci_alloc_consistent(adapter->pci_device,
- blk_size, &blkp);
- if (blk_pointer == NULL)
- break;
- blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp);
- }
- if (adapter->alloc_ccbs > prev_alloc) {
- if (print_success)
- blogic_notice("Allocated %d additional CCBs (total now %d)\n", adapter, adapter->alloc_ccbs - prev_alloc, adapter->alloc_ccbs);
- return;
- }
- blogic_notice("Failed to allocate additional CCBs\n", adapter);
- if (adapter->drvr_qdepth > adapter->alloc_ccbs - adapter->tgt_count) {
- adapter->drvr_qdepth = adapter->alloc_ccbs - adapter->tgt_count;
- adapter->scsi_host->can_queue = adapter->drvr_qdepth;
- }
- }
- /*
- blogic_alloc_ccb allocates a CCB from Host Adapter's free list,
- allocating more memory from the Kernel if necessary. The Host Adapter's
- Lock should already have been acquired by the caller.
- */
- static struct blogic_ccb *blogic_alloc_ccb(struct blogic_adapter *adapter)
- {
- static unsigned long serial;
- struct blogic_ccb *ccb;
- ccb = adapter->free_ccbs;
- if (ccb != NULL) {
- ccb->serial = ++serial;
- adapter->free_ccbs = ccb->next;
- ccb->next = NULL;
- if (adapter->free_ccbs == NULL)
- blogic_create_addlccbs(adapter, adapter->inc_ccbs,
- true);
- return ccb;
- }
- blogic_create_addlccbs(adapter, adapter->inc_ccbs, true);
- ccb = adapter->free_ccbs;
- if (ccb == NULL)
- return NULL;
- ccb->serial = ++serial;
- adapter->free_ccbs = ccb->next;
- ccb->next = NULL;
- return ccb;
- }
- /*
- blogic_dealloc_ccb deallocates a CCB, returning it to the Host Adapter's
- free list. The Host Adapter's Lock should already have been acquired by the
- caller.
- */
- static void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap)
- {
- struct blogic_adapter *adapter = ccb->adapter;
- if (ccb->command != NULL)
- scsi_dma_unmap(ccb->command);
- if (dma_unmap)
- pci_unmap_single(adapter->pci_device, ccb->sensedata,
- ccb->sense_datalen, PCI_DMA_FROMDEVICE);
- ccb->command = NULL;
- ccb->status = BLOGIC_CCB_FREE;
- ccb->next = adapter->free_ccbs;
- adapter->free_ccbs = ccb;
- }
- /*
- blogic_cmd sends the command opcode to adapter, optionally
- providing paramlen bytes of param and receiving at most
- replylen bytes of reply; any excess reply data is received but
- discarded.
- On success, this function returns the number of reply bytes read from
- the Host Adapter (including any discarded data); on failure, it returns
- -1 if the command was invalid, or -2 if a timeout occurred.
- blogic_cmd is called exclusively during host adapter detection and
- initialization, so performance and latency are not critical, and exclusive
- access to the Host Adapter hardware is assumed. Once the host adapter and
- driver are initialized, the only Host Adapter command that is issued is the
- single byte Execute Mailbox Command operation code, which does not require
- waiting for the Host Adapter Ready bit to be set in the Status Register.
- */
- static int blogic_cmd(struct blogic_adapter *adapter, enum blogic_opcode opcode,
- void *param, int paramlen, void *reply, int replylen)
- {
- unsigned char *param_p = (unsigned char *) param;
- unsigned char *reply_p = (unsigned char *) reply;
- union blogic_stat_reg statusreg;
- union blogic_int_reg intreg;
- unsigned long processor_flag = 0;
- int reply_b = 0, result;
- long timeout;
- /*
- Clear out the Reply Data if provided.
- */
- if (replylen > 0)
- memset(reply, 0, replylen);
- /*
- If the IRQ Channel has not yet been acquired, then interrupts
- must be disabled while issuing host adapter commands since a
- Command Complete interrupt could occur if the IRQ Channel was
- previously enabled by another BusLogic Host Adapter or another
- driver sharing the same IRQ Channel.
- */
- if (!adapter->irq_acquired)
- local_irq_save(processor_flag);
- /*
- Wait for the Host Adapter Ready bit to be set and the
- Command/Parameter Register Busy bit to be reset in the Status
- Register.
- */
- timeout = 10000;
- while (--timeout >= 0) {
- statusreg.all = blogic_rdstatus(adapter);
- if (statusreg.sr.adapter_ready && !statusreg.sr.cmd_param_busy)
- break;
- udelay(100);
- }
- if (timeout < 0) {
- blogic_cmd_failure_reason =
- "Timeout waiting for Host Adapter Ready";
- result = -2;
- goto done;
- }
- /*
- Write the opcode to the Command/Parameter Register.
- */
- adapter->adapter_cmd_complete = false;
- blogic_setcmdparam(adapter, opcode);
- /*
- Write any additional Parameter Bytes.
- */
- timeout = 10000;
- while (paramlen > 0 && --timeout >= 0) {
- /*
- Wait 100 microseconds to give the Host Adapter enough
- time to determine whether the last value written to the
- Command/Parameter Register was valid or not. If the
- Command Complete bit is set in the Interrupt Register,
- then the Command Invalid bit in the Status Register will
- be reset if the Operation Code or Parameter was valid
- and the command has completed, or set if the Operation
- Code or Parameter was invalid. If the Data In Register
- Ready bit is set in the Status Register, then the
- Operation Code was valid, and data is waiting to be read
- back from the Host Adapter. Otherwise, wait for the
- Command/Parameter Register Busy bit in the Status
- Register to be reset.
- */
- udelay(100);
- intreg.all = blogic_rdint(adapter);
- statusreg.all = blogic_rdstatus(adapter);
- if (intreg.ir.cmd_complete)
- break;
- if (adapter->adapter_cmd_complete)
- break;
- if (statusreg.sr.datain_ready)
- break;
- if (statusreg.sr.cmd_param_busy)
- continue;
- blogic_setcmdparam(adapter, *param_p++);
- paramlen--;
- }
- if (timeout < 0) {
- blogic_cmd_failure_reason =
- "Timeout waiting for Parameter Acceptance";
- result = -2;
- goto done;
- }
- /*
- The Modify I/O Address command does not cause a Command Complete
- Interrupt.
- */
- if (opcode == BLOGIC_MOD_IOADDR) {
- statusreg.all = blogic_rdstatus(adapter);
- if (statusreg.sr.cmd_invalid) {
- blogic_cmd_failure_reason =
- "Modify I/O Address Invalid";
- result = -1;
- goto done;
- }
- if (blogic_global_options.trace_config)
- blogic_notice("blogic_cmd(%02X) Status = %02X: " "(Modify I/O Address)\n", adapter, opcode, statusreg.all);
- result = 0;
- goto done;
- }
- /*
- Select an appropriate timeout value for awaiting command completion.
- */
- switch (opcode) {
- case BLOGIC_INQ_DEV0TO7:
- case BLOGIC_INQ_DEV8TO15:
- case BLOGIC_INQ_DEV:
- /* Approximately 60 seconds. */
- timeout = 60 * 10000;
- break;
- default:
- /* Approximately 1 second. */
- timeout = 10000;
- break;
- }
- /*
- Receive any Reply Bytes, waiting for either the Command
- Complete bit to be set in the Interrupt Register, or for the
- Interrupt Handler to set the Host Adapter Command Completed
- bit in the Host Adapter structure.
- */
- while (--timeout >= 0) {
- intreg.all = blogic_rdint(adapter);
- statusreg.all = blogic_rdstatus(adapter);
- if (intreg.ir.cmd_complete)
- break;
- if (adapter->adapter_cmd_complete)
- break;
- if (statusreg.sr.datain_ready) {
- if (++reply_b <= replylen)
- *reply_p++ = blogic_rddatain(adapter);
- else
- blogic_rddatain(adapter);
- }
- if (opcode == BLOGIC_FETCH_LOCALRAM &&
- statusreg.sr.adapter_ready)
- break;
- udelay(100);
- }
- if (timeout < 0) {
- blogic_cmd_failure_reason =
- "Timeout waiting for Command Complete";
- result = -2;
- goto done;
- }
- /*
- Clear any pending Command Complete Interrupt.
- */
- blogic_intreset(adapter);
- /*
- Provide tracing information if requested.
- */
- if (blogic_global_options.trace_config) {
- int i;
- blogic_notice("blogic_cmd(%02X) Status = %02X: %2d ==> %2d:",
- adapter, opcode, statusreg.all, replylen,
- reply_b);
- if (replylen > reply_b)
- replylen = reply_b;
- for (i = 0; i < replylen; i++)
- blogic_notice(" %02X", adapter,
- ((unsigned char *) reply)[i]);
- blogic_notice("\n", adapter);
- }
- /*
- Process Command Invalid conditions.
- */
- if (statusreg.sr.cmd_invalid) {
- /*
- Some early BusLogic Host Adapters may not recover
- properly from a Command Invalid condition, so if this
- appears to be the case, a Soft Reset is issued to the
- Host Adapter. Potentially invalid commands are never
- attempted after Mailbox Initialization is performed,
- so there should be no Host Adapter state lost by a
- Soft Reset in response to a Command Invalid condition.
- */
- udelay(1000);
- statusreg.all = blogic_rdstatus(adapter);
- if (statusreg.sr.cmd_invalid || statusreg.sr.rsvd ||
- statusreg.sr.datain_ready ||
- statusreg.sr.cmd_param_busy ||
- !statusreg.sr.adapter_ready ||
- !statusreg.sr.init_reqd ||
- statusreg.sr.diag_active ||
- statusreg.sr.diag_failed) {
- blogic_softreset(adapter);
- udelay(1000);
- }
- blogic_cmd_failure_reason = "Command Invalid";
- result = -1;
- goto done;
- }
- /*
- Handle Excess Parameters Supplied conditions.
- */
- if (paramlen > 0) {
- blogic_cmd_failure_reason = "Excess Parameters Supplied";
- result = -1;
- goto done;
- }
- /*
- Indicate the command completed successfully.
- */
- blogic_cmd_failure_reason = NULL;
- result = reply_b;
- /*
- Restore the interrupt status if necessary and return.
- */
- done:
- if (!adapter->irq_acquired)
- local_irq_restore(processor_flag);
- return result;
- }
- /*
- blogic_add_probeaddr_isa appends a single ISA I/O Address to the list
- of I/O Address and Bus Probe Information to be checked for potential BusLogic
- Host Adapters.
- */
- static void __init blogic_add_probeaddr_isa(unsigned long io_addr)
- {
- struct blogic_probeinfo *probeinfo;
- if (blogic_probeinfo_count >= BLOGIC_MAX_ADAPTERS)
- return;
- probeinfo = &blogic_probeinfo_list[blogic_probeinfo_count++];
- probeinfo->adapter_type = BLOGIC_MULTIMASTER;
- probeinfo->adapter_bus_type = BLOGIC_ISA_BUS;
- probeinfo->io_addr = io_addr;
- probeinfo->pci_device = NULL;
- }
- /*
- blogic_init_probeinfo_isa initializes the list of I/O Address and
- Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters
- only from the list of standard BusLogic MultiMaster ISA I/O Addresses.
- */
- static void __init blogic_init_probeinfo_isa(struct blogic_adapter *adapter)
- {
- /*
- If BusLogic Driver Options specifications requested that ISA
- Bus Probes be inhibited, do not proceed further.
- */
- if (blogic_probe_options.noprobe_isa)
- return;
- /*
- Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
- */
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe330)
- blogic_add_probeaddr_isa(0x330);
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe334)
- blogic_add_probeaddr_isa(0x334);
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe230)
- blogic_add_probeaddr_isa(0x230);
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe234)
- blogic_add_probeaddr_isa(0x234);
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe130)
- blogic_add_probeaddr_isa(0x130);
- if (!blogic_probe_options.limited_isa || blogic_probe_options.probe134)
- blogic_add_probeaddr_isa(0x134);
- }
- #ifdef CONFIG_PCI
- /*
- blogic_sort_probeinfo sorts a section of blogic_probeinfo_list in order
- of increasing PCI Bus and Device Number.
- */
- static void __init blogic_sort_probeinfo(struct blogic_probeinfo
- *probeinfo_list, int probeinfo_cnt)
- {
- int last_exchange = probeinfo_cnt - 1, bound, j;
- while (last_exchange > 0) {
- bound = last_exchange;
- last_exchange = 0;
- for (j = 0; j < bound; j++) {
- struct blogic_probeinfo *probeinfo1 =
- &probeinfo_list[j];
- struct blogic_probeinfo *probeinfo2 =
- &probeinfo_list[j + 1];
- if (probeinfo1->bus > probeinfo2->bus ||
- (probeinfo1->bus == probeinfo2->bus &&
- (probeinfo1->dev > probeinfo2->dev))) {
- struct blogic_probeinfo tmp_probeinfo;
- memcpy(&tmp_probeinfo, probeinfo1,
- sizeof(struct blogic_probeinfo));
- memcpy(probeinfo1, probeinfo2,
- sizeof(struct blogic_probeinfo));
- memcpy(probeinfo2, &tmp_probeinfo,
- sizeof(struct blogic_probeinfo));
- last_exchange = j;
- }
- }
- }
- }
- /*
- blogic_init_mm_probeinfo initializes the list of I/O Address
- and Bus Probe Information to be checked for potential BusLogic MultiMaster
- SCSI Host Adapters by interrogating the PCI Configuration Space on PCI
- machines as well as from the list of standard BusLogic MultiMaster ISA
- I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found.
- */
- static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
- {
- struct blogic_probeinfo *pr_probeinfo =
- &blogic_probeinfo_list[blogic_probeinfo_count];
- int nonpr_mmindex = blogic_probeinfo_count + 1;
- int nonpr_mmcount = 0, mmcount = 0;
- bool force_scan_order = false;
- bool force_scan_order_checked = false;
- bool addr_seen[6];
- struct pci_dev *pci_device = NULL;
- int i;
- if (blogic_probeinfo_count >= BLOGIC_MAX_ADAPTERS)
- return 0;
- blogic_probeinfo_count++;
- for (i = 0; i < 6; i++)
- addr_seen[i] = false;
- /*
- Iterate over the MultiMaster PCI Host Adapters. For each
- enumerated host adapter, determine whether its ISA Compatible
- I/O Port is enabled and if so, whether it is assigned the
- Primary I/O Address. A host adapter that is assigned the
- Primary I/O Address will always be the preferred boot device.
- The MultiMaster BIOS will first recognize a host adapter at
- the Primary I/O Address, then any other PCI host adapters,
- and finally any host adapters located at the remaining
- standard ISA I/O Addresses. When a PCI host adapter is found
- with its ISA Compatible I/O Port enabled, a command is issued
- to disable the ISA Compatible I/O Port, and it is noted that the
- particular standard ISA I/O Address need not be probed.
- */
- pr_probeinfo->io_addr = 0;
- while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC,
- PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
- pci_device)) != NULL) {
- struct blogic_adapter *host_adapter = adapter;
- struct blogic_adapter_info adapter_info;
- enum blogic_isa_ioport mod_ioaddr_req;
- unsigned char bus;
- unsigned char device;
- unsigned int irq_ch;
- unsigned long base_addr0;
- unsigned long base_addr1;
- unsigned long io_addr;
- unsigned long pci_addr;
- if (pci_enable_device(pci_device))
- continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
- continue;
- bus = pci_device->bus->number;
- device = pci_device->devfn >> 3;
- irq_ch = pci_device->irq;
- io_addr = base_addr0 = pci_resource_start(pci_device, 0);
- pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
- if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
- blogic_err("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, base_addr0);
- blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
- continue;
- }
- if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
- blogic_err("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, base_addr1);
- blogic_err("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, bus, device, pci_addr);
- continue;
- }
- if (irq_ch == 0) {
- blogic_err("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, irq_ch);
- blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
- continue;
- }
- if (blogic_global_options.trace_probe) {
- blogic_notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL);
- blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, bus, device, io_addr, pci_addr);
- }
- /*
- Issue the Inquire PCI Host Adapter Information command to determine
- the ISA Compatible I/O Port. If the ISA Compatible I/O Port is
- known and enabled, note that the particular Standard ISA I/O
- Address should not be probed.
- */
- host_adapter->io_addr = io_addr;
- blogic_intreset(host_adapter);
- if (blogic_cmd(host_adapter, BLOGIC_INQ_PCI_INFO, NULL, 0,
- &adapter_info, sizeof(adapter_info)) ==
- sizeof(adapter_info)) {
- if (adapter_info.isa_port < 6)
- addr_seen[adapter_info.isa_port] = true;
- } else
- adapter_info.isa_port = BLOGIC_IO_DISABLE;
- /*
- Issue the Modify I/O Address command to disable the
- ISA Compatible I/O Port. On PCI Host Adapters, the
- Modify I/O Address command allows modification of the
- ISA compatible I/O Address that the Host Adapter
- responds to; it does not affect the PCI compliant
- I/O Address assigned at system initialization.
- */
- mod_ioaddr_req = BLOGIC_IO_DISABLE;
- blogic_cmd(host_adapter, BLOGIC_MOD_IOADDR, &mod_ioaddr_req,
- sizeof(mod_ioaddr_req), NULL, 0);
- /*
- For the first MultiMaster Host Adapter enumerated,
- issue the Fetch Host Adapter Local RAM command to read
- byte 45 of the AutoSCSI area, for the setting of the
- "Use Bus And Device # For PCI Scanning Seq." option.
- Issue the Inquire Board ID command since this option is
- only valid for the BT-948/958/958D.
- */
- if (!force_scan_order_checked) {
- struct blogic_fetch_localram fetch_localram;
- struct blogic_autoscsi_byte45 autoscsi_byte45;
- struct blogic_board_id id;
- fetch_localram.offset = BLOGIC_AUTOSCSI_BASE + 45;
- fetch_localram.count = sizeof(autoscsi_byte45);
- blogic_cmd(host_adapter, BLOGIC_FETCH_LOCALRAM,
- &fetch_localram, sizeof(fetch_localram),
- &autoscsi_byte45,
- sizeof(autoscsi_byte45));
- blogic_cmd(host_adapter, BLOGIC_GET_BOARD_ID, NULL, 0,
- &id, sizeof(id));
- if (id.fw_ver_digit1 == '5')
- force_scan_order =
- autoscsi_byte45.force_scan_order;
- force_scan_order_checked = true;
- }
- /*
- Determine whether this MultiMaster Host Adapter has its
- ISA Compatible I/O Port enabled and is assigned the
- Primary I/O Address. If it does, then it is the Primary
- MultiMaster Host Adapter and must be recognized first.
- If it does not, then it is added to the list for probing
- after any Primary MultiMaster Host Adapter is probed.
- */
- if (adapter_info.isa_port == BLOGIC_IO_330) {
- pr_probeinfo->adapter_type = BLOGIC_MULTIMASTER;
- pr_probeinfo->adapter_bus_type = BLOGIC_PCI_BUS;
- pr_probeinfo->io_addr = io_addr;
- pr_probeinfo->pci_addr = pci_addr;
- pr_probeinfo->bus = bus;
- pr_probeinfo->dev = device;
- pr_probeinfo->irq_ch = irq_ch;
- pr_probeinfo->pci_device = pci_dev_get(pci_device);
- mmcount++;
- } else if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) {
- struct blogic_probeinfo *probeinfo =
- &blogic_probeinfo_list[blogic_probeinfo_count++];
- probeinfo->adapter_type = BLOGIC_MULTIMASTER;
- probeinfo->adapter_bus_type = BLOGIC_PCI_BUS;
- probeinfo->io_addr = io_addr;
- probeinfo->pci_addr = pci_addr;
- probeinfo->bus = bus;
- probeinfo->dev = device;
- probeinfo->irq_ch = irq_ch;
- probeinfo->pci_device = pci_dev_get(pci_device);
- nonpr_mmcount++;
- mmcount++;
- } else
- blogic_warn("BusLogic: Too many Host Adapters " "detected\n", NULL);
- }
- /*
- If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq."
- option is ON for the first enumerated MultiMaster Host Adapter,
- and if that host adapter is a BT-948/958/958D, then the
- MultiMaster BIOS will recognize MultiMaster Host Adapters in
- the order of increasing PCI Bus and Device Number. In that case,
- sort the probe information into the same order the BIOS uses.
- If this option is OFF, then the MultiMaster BIOS will recognize
- MultiMaster Host Adapters in the order they are enumerated by
- the PCI BIOS, and hence no sorting is necessary.
- */
- if (force_scan_order)
- blogic_sort_probeinfo(&blogic_probeinfo_list[nonpr_mmindex],
- nonpr_mmcount);
- /*
- If no PCI MultiMaster Host Adapter is assigned the Primary
- I/O Address, then the Primary I/O Address must be probed
- explicitly before any PCI host adapters are probed.
- */
- if (!blogic_probe_options.noprobe_isa)
- if (pr_probeinfo->io_addr == 0 &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe330)) {
- pr_probeinfo->adapter_type = BLOGIC_MULTIMASTER;
- pr_probeinfo->adapter_bus_type = BLOGIC_ISA_BUS;
- pr_probeinfo->io_addr = 0x330;
- }
- /*
- Append the list of standard BusLogic MultiMaster ISA I/O Addresses,
- omitting the Primary I/O Address which has already been handled.
- */
- if (!blogic_probe_options.noprobe_isa) {
- if (!addr_seen[1] &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe334))
- blogic_add_probeaddr_isa(0x334);
- if (!addr_seen[2] &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe230))
- blogic_add_probeaddr_isa(0x230);
- if (!addr_seen[3] &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe234))
- blogic_add_probeaddr_isa(0x234);
- if (!addr_seen[4] &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe130))
- blogic_add_probeaddr_isa(0x130);
- if (!addr_seen[5] &&
- (!blogic_probe_options.limited_isa ||
- blogic_probe_options.probe134))
- blogic_add_probeaddr_isa(0x134);
- }
- /*
- Iterate over the older non-compliant MultiMaster PCI Host Adapters,
- noting the PCI bus location and assigned IRQ Channel.
- */
- pci_device = NULL;
- while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC,
- PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
- pci_device)) != NULL) {
- unsigned char bus;
- unsigned char device;
- unsigned int irq_ch;
- unsigned long io_addr;
- if (pci_enable_device(pci_device))
- continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
- continue;
- bus = pci_device->bus->number;
- device = pci_device->devfn >> 3;
- irq_ch = pci_device->irq;
- io_addr = pci_resource_start(pci_device, 0);
- if (io_addr == 0 || irq_ch == 0)
- continue;
- for (i = 0; i < blogic_probeinfo_count; i++) {
- struct blogic_probeinfo *probeinfo =
- &blogic_probeinfo_list[i];
- if (probeinfo->io_addr == io_addr &&
- probeinfo->adapter_type == BLOGIC_MULTIMASTER) {
- probeinfo->adapter_bus_type = BLOGIC_PCI_BUS;
- probeinfo->pci_addr = 0;
- probeinfo->bus = bus;
- probeinfo->dev = device;
- probeinfo->irq_ch = irq_ch;
- probeinfo->pci_device = pci_dev_get(pci_device);
- break;
- }
- }
- }
- return mmcount;
- }
- /*
- blogic_init_fp_probeinfo initializes the list of I/O Address
- and Bus Probe Information to be checked for potential BusLogic FlashPoint
- Host Adapters by interrogating the PCI Configuration Space. It returns the
- number of FlashPoint Host Adapters found.
- */
- static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter)
- {
- int fpindex = blogic_probeinfo_count, fpcount = 0;
- struct pci_dev *pci_device = NULL;
- /*
- Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
- */
- while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC,
- PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
- pci_device)) != NULL) {
- unsigned char bus;
- unsigned char device;
- unsigned int irq_ch;
- unsigned long base_addr0;
- unsigned long base_addr1;
- unsigned long io_addr;
- unsigned long pci_addr;
- if (pci_enable_device(pci_device))
- continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
- continue;
- bus = pci_device->bus->number;
- device = pci_device->devfn >> 3;
- irq_ch = pci_device->irq;
- io_addr = base_addr0 = pci_resource_start(pci_device, 0);
- pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
- #ifdef CONFIG_SCSI_FLASHPOINT
- if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
- blogic_err("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, base_addr0);
- blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
- continue;
- }
- if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
- blogic_err("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, base_addr1);
- blogic_err("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, bus, device, pci_addr);
- continue;
- }
- if (irq_ch == 0) {
- blogic_err("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, irq_ch);
- blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
- continue;
- }
- if (blogic_global_options.trace_probe) {
- blogic_notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL);
- blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, bus, device, io_addr, pci_addr);
- }
- if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) {
- struct blogic_probeinfo *probeinfo =
- &blogic_probeinfo_list[blogic_probeinfo_count++];
- probeinfo->adapter_type = BLOGIC_FLASHPOINT;
- probeinfo->adapter_bus_type = BLOGIC_PCI_BUS;
- probeinfo->io_addr = io_addr;
- probeinfo->pci_addr = pci_addr;
- probeinfo->bus = bus;
- probeinfo->dev = device;
- probeinfo->irq_ch = irq_ch;
- probeinfo->pci_device = pci_dev_get(pci_device);
- fpcount++;
- } else
- blogic_warn("BusLogic: Too many Host Adapters " "detected\n", NULL);
- #else
- blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, bus, device);
- blogic_err("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, io_addr, pci_addr, irq_ch);
- blogic_err("BusLogic: support was omitted in this kernel " "configuration.\n", NULL);
- #endif
- }
- /*
- The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of
- increasing PCI Bus and Device Number, so sort the probe information into
- the same order the BIOS uses.
- */
- blogic_sort_probeinfo(&blogic_probeinfo_list[fpindex], fpcount);
- return fpcount;
- }
- /*
- blogic_init_probeinfo_list initializes the list of I/O Address and Bus
- Probe Information to be checked for potential BusLogic SCSI Host Adapters by
- interrogating the PCI Configuration Space on PCI machines as well as from the
- list of standard BusLogic MultiMaster ISA I/O Addresses. By default, if both
- FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
- probe for FlashPoint Host Adapters first unless the BIOS primary disk is
- controlled by the first PCI MultiMaster Host Adapter, in which case
- MultiMaster Host Adapters will be probed first. The BusLogic Driver Options
- specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force
- a particular probe order.
- */
- static void __init blogic_init_probeinfo_list(struct blogic_adapter *adapter)
- {
- /*
- If a PCI BIOS is present, interrogate it for MultiMaster and
- FlashPoint Host Adapters; otherwise, default to the standard
- ISA MultiMaster probe.
- */
- if (!blogic_probe_options.noprobe_pci) {
- if (blogic_probe_options.multimaster_first) {
- blogic_init_mm_probeinfo(adapter);
- blogic_init_fp_probeinfo(adapter);
- } else if (blogic_probe_options.flashpoint_first) {
- blogic_init_fp_probeinfo(adapter);
- blogic_init_mm_probeinfo(adapter);
- } else {
- int fpcount = blogic_init_fp_probeinfo(adapter);
- int mmcount = blogic_init_mm_probeinfo(adapter);
- if (fpcount > 0 && mmcount > 0) {
- struct blogic_probeinfo *probeinfo =
- &blogic_probeinfo_list[fpcount];
- struct blogic_adapter *myadapter = adapter;
- struct blogic_fetch_localram fetch_localram;
- struct blogic_bios_drvmap d0_mapbyte;
- while (probeinfo->adapter_bus_type !=
- BLOGIC_PCI_BUS)
- probeinfo++;
- myadapter->io_addr = probeinfo->io_addr;
- fetch_localram.offset =
- BLOGIC_BIOS_BASE + BLOGIC_BIOS_DRVMAP;
- fetch_localram.count = sizeof(d0_mapbyte);
- blogic_cmd(myadapter, BLOGIC_FETCH_LOCALRAM,
- &fetch_localram,
- sizeof(fetch_localram),
- &d0_mapbyte,
- sizeof(d0_mapbyte));
- /*
- If the Map Byte for BIOS Drive 0 indicates
- that BIOS Drive 0 is controlled by this
- PCI MultiMaster Host Adapter, then reverse
- the probe order so that MultiMaster Host
- Adapters are probed before FlashPoint Host
- Adapters.
- */
- if (d0_mapbyte.diskgeom != BLOGIC_BIOS_NODISK) {
- struct blogic_probeinfo saved_probeinfo[BLOGIC_MAX_ADAPTERS];
- int mmcount = blogic_probeinfo_count - fpcount;
- memcpy(saved_probeinfo,
- blogic_probeinfo_list,
- blogic_probeinfo_count * sizeof(struct blogic_probeinfo));
- memcpy(&blogic_probeinfo_list[0],
- &saved_probeinfo[fpcount],
- mmcount * sizeof(struct blogic_probeinfo));
- memcpy(&blogic_probeinfo_list[mmcount],
- &saved_probeinfo[0],
- fpcount * sizeof(struct blogic_probeinfo));
- }
- }
- }
- } else {
- blogic_init_probeinfo_isa(adapter);
- }
- }
- #else
- #define blogic_init_probeinfo_list(adapter) \
- blogic_init_probeinfo_isa(adapter)
- #endif /* CONFIG_PCI */
- /*
- blogic_failure prints a standardized error message, and then returns false.
- */
- static bool blogic_failure(struct blogic_adapter *adapter, char *msg)
- {
- blogic_announce_drvr(adapter);
- if (adapter->adapter_bus_type == BLOGIC_PCI_BUS) {
- blogic_err("While configuring BusLogic PCI Host Adapter at\n",
- adapter);
- blogic_err("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", adapter, adapter->bus, adapter->dev, adapter->io_addr, adapter->pci_addr);
- } else
- blogic_err("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", adapter, adapter->io_addr);
- blogic_err("%s FAILED - DETACHING\n", adapter, msg);
- if (blogic_cmd_failure_reason != NULL)
- blogic_err("ADDITIONAL FAILURE INFO - %s\n", adapter,
- blogic_cmd_failure_reason);
- return false;
- }
- /*
- blogic_probe probes for a BusLogic Host Adapter.
- */
- static bool __init blogic_probe(struct blogic_adapter *adapter)
- {
- union blogic_stat_reg statusreg;
- union blogic_int_reg intreg;
- union blogic_geo_reg georeg;
- /*
- FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager.
- */
- if (blogic_flashpoint_type(adapter)) {
- struct fpoint_info *fpinfo = &adapter->fpinfo;
- fpinfo->base_addr = (u32) adapter->io_addr;
- fpinfo->irq_ch = adapter->irq_ch;
- fpinfo->present = false;
- if (!(FlashPoint_ProbeHostAdapter(fpinfo) == 0 &&
- fpinfo->present)) {
- blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", adapter, adapter->bus, adapter->dev);
- blogic_err("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", adapter, adapter->io_addr, adapter->pci_addr);
- blogic_err("BusLogic: Probe Function failed to validate it.\n", adapter);
- return false;
- }
- if (blogic_global_options.trace_probe)
- blogic_notice("BusLogic_Probe(0x%X): FlashPoint Found\n", adapter, adapter->io_addr);
- /*
- Indicate the Host Adapter Probe completed successfully.
- */
- return true;
- }
- /*
- Read the Status, Interrupt, and Geometry Registers to test if there are I/O
- ports that respond, and to check the values to determine if they are from a
- BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which
- case there is definitely no BusLogic Host Adapter at this base I/O Address.
- The test here is a subset of that used by the BusLogic Host Adapter BIOS.
- */
- statusreg.all = blogic_rdstatus(adapter);
- intreg.all = blogic_rdint(adapter);
- georeg.all = blogic_rdgeom(adapter);
- if (blogic_global_options.trace_probe)
- blogic_notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", adapter, adapter->io_addr, statusreg.all, intreg.all, georeg.all);
- if (statusreg.all == 0 || statusreg.sr.diag_active ||
- statusreg.sr.cmd_param_busy || statusreg.sr.rsvd ||
- statusreg.sr.cmd_invalid || intreg.ir.rsvd != 0)
- return false;
- /*
- Check the undocumented Geometry Register to test if there is
- an I/O port that responded. Adaptec Host Adapters do not
- implement the Geometry Register, so this test helps serve to
- avoid incorrectly recognizing an Adaptec 1542A or 1542B as a
- BusLogic. Unfortunately, the Adaptec 1542C series does respond
- to the Geometry Register I/O port, but it will be rejected
- later when the Inquire Extended Setup Information command is
- issued in blogic_checkadapter. The AMI FastDisk Host Adapter
- is a BusLogic clone that implements the same interface as
- earlier BusLogic Host Adapters, including the undocumented
- commands, and is therefore supported by this driver. However,
- the AMI FastDisk always returns 0x00 upon reading the Geometry
- Register, so the extended translation option should always be
- left disabled on the AMI FastDisk.
- */
- if (georeg.all == 0xFF)
- return false;
- /*
- Indicate the Host Adapter Probe completed successfully.
- */
- return true;
- }
- /*
- blogic_hwreset issues a Hardware Reset to the Host Adapter
- and waits for Host Adapter Diagnostics to complete. If hard_reset is true, a
- Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a
- Soft Reset is performed which only resets the Host Adapter without forcing a
- SCSI Bus Reset.
- */
- static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
- {
- union blogic_stat_reg statusreg;
- int timeout;
- /*
- FlashPoint Host Adapters are Hard Reset by the FlashPoint
- SCCB Manager.
- */
- if (blogic_flashpoint_type(adapter)) {
- struct fpoint_info *fpinfo = &adapter->fpinfo;
- fpinfo->softreset = !hard_reset;
- fpinfo->report_underrun = true;
- adapter->cardhandle =
- FlashPoint_HardwareResetHostAdapter(fpinfo);
- if (adapter->cardhandle == (void *)FPOINT_BADCARD_HANDLE)
- return false;
- /*
- Indicate the Host Adapter Hard Reset completed successfully.
- */
- return true;
- }
- /*
- Issue a Hard Reset or Soft Reset Command to the Host Adapter.
- The Host Adapter should respond by setting Diagnostic Active in
- the Status Register.
- */
- if (hard_reset)
- blogic_hardreset(adapter);
- else
- blogic_softreset(adapter);
- /*
- Wait until Diagnostic Active is set in the Status Register.
- */
- timeout = 5 * 10000;
- while (--timeout >= 0) {
- statusreg.all = blogic_rdstatus(adapter);
- if (statusreg.sr.diag_active)
- break;
- udelay(100);
- }
- if (blogic_global_options.trace_hw_reset)
- blogic_notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
- if (timeout < 0)
- return false;
- /*
- Wait 100 microseconds to allow completion of any initial diagnostic
- activity which might leave the contents of the Status Register
- unpredictable.
- */
- udelay(100);
- /*
- Wait until Diagnostic Active is reset in the Status Register.
- */
- timeout = 10 * 10000;
- while (--timeout >= 0) {
- statusreg.all = blogic_rdstatus(adapter);
- if (!statusreg.sr.diag_active)
- break;
- udelay(100);
- }
- if (blogic_global_options.trace_hw_reset)
- blogic_notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
- if (timeout < 0)
- return false;
- /*
- Wait until at least one of the Diagnostic Failure, Host Adapter
- Ready, or Data In Register Ready bits is set in the Status Register.
- */
- timeout = 10000;
- while (--timeout >= 0) {
- statusreg.all = blogic_rdstatus(adapter);
- if (statusreg.sr.diag_failed || statusreg.sr.adapter_ready ||
- statusreg.sr.datain_ready)
- break;
- udelay(100);
- }
- if (blogic_global_options.trace_hw_reset)
- blogic_notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
- if (timeout < 0)
- return false;
- /*
- If Diagnostic Failure is set or Host Adapter Ready is reset,
- then an error occurred during the Host Adapter diagnostics.
- If Data In Register Ready is set, then there is an Error Code
- available.
- */
- if (statusreg.sr.diag_failed || !statusreg.sr.adapter_ready) {
- blogic_cmd_failure_reason = NULL;
- blogic_failure(adapter, "HARD RESET DIAGNOSTICS");
- blogic_err("HOST ADAPTER STATUS REGISTER = %02X\n", adapter,
- statusreg.all);
- if (statusreg.sr.datain_ready)
- blogic_err("HOST ADAPTER ERROR CODE = %d\n", adapter,
- blogic_rddatain(adapter));
- return false;
- }
- /*
- Indicate the Host Adapter Hard Reset completed successfully.
- */
- return true;
- }
- /*
- blogic_checkadapter checks to be sure this really is a BusLogic
- Host Adapter.
- */
- static bool __init blogic_checkadapter(struct blogic_adapter *adapter)
- {
- struct blogic_ext_setup ext_setupinfo;
- unsigned char req_replylen;
- bool result = true;
- /*
- FlashPoint Host Adapters do not require this protection.
- */
- if (blogic_flashpoint_type(adapter))
- return true;
- /*
- Issue the Inquire Extended Setup Information command. Only genuine
- BusLogic Host Adapters and true clones support this command.
- Adaptec 1542C series Host Adapters that respond to the Geometry
- Register I/O port will fail this command.
- */
- req_replylen = sizeof(ext_setupinfo);
- if (blogic_cmd(adapter, BLOGIC_INQ_EXTSETUP, &req_replylen,
- sizeof(req_replylen), &ext_setupinfo,
- sizeof(ext_setupinfo)) != sizeof(ext_setupinfo))
- result = false;
- /*
- Provide tracing information if requested and return.
- */
- if (blogic_global_options.trace_probe)
- blogic_notice("BusLogic_Check(0x%X): MultiMaster %s\n", adapter,
- adapter->io_addr,
- (result ? "Found" : "Not Found"));
- return result;
- }
- /*
- blogic_rdconfig reads the Configuration Information
- from Host Adapter and initializes the Host Adapter structure.
- */
- static bool __init blogic_rdconfig(struct blogic_adapter *adapter)
- {
- struct blogic_board_id id;
- struct blogic_config config;
- struct blogic_setup_info setupinfo;
- struct blogic_ext_setup ext_setupinfo;
- unsigned char model[5];
- unsigned char fw_ver_digit3;
- unsigned char fw_ver_letter;
- struct blogic_adapter_info adapter_info;
- struct blogic_fetch_localram fetch_localram;
- struct blogic_autoscsi autoscsi;
- union blogic_geo_reg georeg;
- unsigned char req_replylen;
- unsigned char *tgt, ch;
- int tgt_id, i;
- /*
- Configuration Information for FlashPoint Host Adapters is
- provided in the fpoint_info structure by the FlashPoint
- SCCB Manager's Probe Function. Initialize fields in the
- Host Adapter structure from the fpoint_info structure.
- */
- if (blogic_flashpoint_type(adapter)) {
- struct fpoint_info *fpinfo = &adapter->fpinfo;
- tgt = adapter->model;
- *tgt++ = 'B';
- *tgt++ = 'T';
- *tgt++ = '-';
- for (i = 0; i < sizeof(fpinfo->model); i++)
- *tgt++ = fpinfo->model[i];
- *tgt++ = '\0';
- strcpy(adapter->fw_ver, FLASHPOINT_FW_VER);
- adapter->scsi_id = fpinfo->scsi_id;
- adapter->ext_trans_enable = fpinfo->ext_trans_enable;
- adapter->parity = fpinfo->parity;
- adapter->reset_enabled = !fpinfo->softreset;
- adapter->level_int = true;
- adapter->wide = fpinfo->wide;
- adapter->differential = false;
- adapter->scam = true;
- adapter->ultra = true;
- adapter->ext_lun = true;
- adapter->terminfo_valid = true;
- adapter->low_term = fpinfo->low_term;
- adapter->high_term = fpinfo->high_term;
- adapter->scam_enabled = fpinfo->scam_enabled;
- adapter->scam_lev2 = fpinfo->scam_lev2;
- adapter->drvr_sglimit = BLOGIC_SG_LIMIT;
- adapter->maxdev = (adapter->wide ? 16 : 8);
- adapter->maxlun = 32;
- adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE;
- adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE;
- adapter->drvr_qdepth = 255;
- adapter->adapter_qdepth = adapter->drvr_qdepth;
- adapter->sync_ok = fpinfo->sync_ok;
- adapter->fast_ok = fpinfo->fast_ok;
- adapter->ultra_ok = fpinfo->ultra_ok;
- adapter->wide_ok = fpinfo->wide_ok;
- adapter->discon_ok = fpinfo->discon_ok;
- adapter->tagq_ok = 0xFFFF;
- goto common;
- }
- /*
- Issue the Inquire Board ID command.
- */
- if (blogic_cmd(adapter, BLOGIC_GET_BOARD_ID, NULL, 0, &id,
- sizeof(id)) != sizeof(id))
- return blogic_failure(adapter, "INQUIRE BOARD ID");
- /*
- Issue the Inquire Configuration command.
- */
- if (blogic_cmd(adapter, BLOGIC_INQ_CONFIG, NULL, 0, &config,
- sizeof(config))
- != sizeof(config))
- return blogic_failure(adapter, "INQUIRE CONFIGURATION");
- /*
- Issue the Inquire Setup Information command.
- */
- req_replylen = sizeof(setupinfo);
- if (blogic_cmd(adapter, BLOGIC_INQ_SETUPINFO, &req_replylen,
- sizeof(req_replylen), &setupinfo,
- sizeof(setupinfo)) != sizeof(setupinfo))
- return blogic_failure(adapter, "INQUIRE SETUP INFORMATION");
- /*
- Issue the Inquire Extended Setup Information command.
- */
- req_replylen = sizeof(ext_setupinfo);
- if (blogic_cmd(adapter, BLOGIC_INQ_EXTSETUP, &req_replylen,
- sizeof(req_replylen), &ext_setupinfo,
- sizeof(ext_setupinfo)) != sizeof(ext_setupinfo))
- return blogic_failure(adapter,
- "INQUIRE EXTENDED SETUP INFORMATION");
- /*
- Issue the Inquire Firmware Version 3rd Digit command.
- */
- fw_ver_digit3 = '\0';
- if (id.fw_ver_digit1 > '0')
- if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_D3, NULL, 0,
- &fw_ver_digit3,
- sizeof(fw_ver_digit3)) != sizeof(fw_ver_digit3))
- return blogic_failure(adapter,
- "INQUIRE FIRMWARE 3RD DIGIT");
- /*
- Issue the Inquire Host Adapter Model Number command.
- */
- if (ext_setupinfo.bus_type == 'A' && id.fw_ver_digit1 == '2')
- /* BusLogic BT-542B ISA 2.xx */
- strcpy(model, "542B");
- else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '2' &&
- (id.fw_ver_digit2 <= '1' || (id.fw_ver_digit2 == '2' &&
- fw_ver_digit3 == '0')))
- /* BusLogic BT-742A EISA 2.1x or 2.20 */
- strcpy(model, "742A");
- else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '0')
- /* AMI FastDisk EISA Series 441 0.x */
- strcpy(model, "747A");
- else {
- req_replylen = sizeof(model);
- if (blogic_cmd(adapter, BLOGIC_INQ_MODELNO, &req_replylen,
- sizeof(req_replylen), &model,
- sizeof(model)) != sizeof(model))
- return blogic_failure(adapter,
- "INQUIRE HOST ADAPTER MODEL NUMBER");
- }
- /*
- BusLogic MultiMaster Host Adapters can be identified by their
- model number and the major version number of their firmware
- as follows:
- 5.xx BusLogic "W" Series Host Adapters:
- BT-948/958/958D
- 4.xx BusLogic "C" Series Host Adapters:
- BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF
- 3.xx BusLogic "S" Series Host Adapters:
- BT-747S/747D/757S/757D/445S/545S/542D
- BT-542B/742A (revision H)
- 2.xx BusLogic "A" Series Host Adapters:
- BT-542B/742A (revision G and below)
- 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
- */
- /*
- Save the Model Name and Host Adapter Name in the Host Adapter
- structure.
- */
- tgt = adapter->model;
- *tgt++ = 'B';
- *tgt++ = 'T';
- *tgt++ = '-';
- for (i = 0; i < sizeof(model); i++) {
- ch = model[i];
- if (ch == ' ' || ch == '\0')
- break;
- *tgt++ = ch;
- }
- *tgt++ = '\0';
- /*
- Save the Firmware Version in the Host Adapter structure.
- */
- tgt = adapter->fw_ver;
- *tgt++ = id.fw_ver_digit1;
- *tgt++ = '.';
- *tgt++ = id.fw_ver_digit2;
- if (fw_ver_digit3 != ' ' && fw_ver_digit3 != '\0')
- *tgt++ = fw_ver_digit3;
- *tgt = '\0';
- /*
- Issue the Inquire Firmware Version Letter command.
- */
- if (strcmp(adapter->fw_ver, "3.3") >= 0) {
- if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_LETTER, NULL, 0,
- &fw_ver_letter,
- sizeof(fw_ver_letter)) != sizeof(fw_ver_letter))
- return blogic_failure(adapter,
- "INQUIRE FIRMWARE VERSION LETTER");
- if (fw_ver_letter != ' ' && fw_ver_letter != '\0')
- *tgt++ = fw_ver_letter;
- *tgt = '\0';
- }
- /*
- Save the Host Adapter SCSI ID in the Host Adapter structure.
- */
- adapter->scsi_id = config.id;
- /*
- Determine the Bus Type and save it in the Host Adapter structure,
- determine and save the IRQ Channel if necessary, and determine
- and save the DMA Channel for ISA Host Adapters.
- */
- adapter->adapter_bus_type =
- blogic_adater_bus_types[adapter->model[3] - '4'];
- if (adapter->irq_ch == 0) {
- if (config.irq_ch9)
- adapter->irq_ch = 9;
- else if (config.irq_ch10)
- adapter->irq_ch = 10;
- else if (config.irq_ch11)
- adapter->irq_ch = 11;
- else if (config.irq_ch12)
- adapter->irq_ch = 12;
- else if (config.irq_ch14)
- adapter->irq_ch = 14;
- else if (config.irq_ch15)
- adapter->irq_ch = 15;
- }
- if (adapter->adapter_bus_type == BLOGIC_ISA_BUS) {
- if (config.dma_ch5)
- adapter->dma_ch = 5;
- else if (config.dma_ch6)
- adapter->dma_ch = 6;
- else if (config.dma_ch7)
- adapter->dma_ch = 7;
- }
- /*
- Determine whether Extended Translation is enabled and save it in
- the Host Adapter structure.
- */
- georeg.all = blogic_rdgeom(adapter);
- adapter->ext_trans_enable = georeg.gr.ext_trans_enable;
- /*
- Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide
- SCSI flag, Differential SCSI flag, SCAM Supported flag, and
- Ultra SCSI flag in the Host Adapter structure.
- */
- adapter->adapter_sglimit = ext_setupinfo.sg_limit;
- adapter->drvr_sglimit = adapter->adapter_sglimit;
- if (adapter->adapter_sglimit > BLOGIC_SG_LIMIT)
- adapter->drvr_sglimit = BLOGIC_SG_LIMIT;
- if (ext_setupinfo.misc.level_int)
- adapter->level_int = true;
- adapter->wide = ext_setupinfo.wide;
- adapter->differential = ext_setupinfo.differential;
- adapter->scam = ext_setupinfo.scam;
- adapter->ultra = ext_setupinfo.ultra;
- /*
- Determine whether Extended LUN Format CCBs are supported and save the
- information in the Host Adapter structure.
- */
- if (adapter->fw_ver[0] == '5' || (adapter->fw_ver[0] == '4' &&
- adapter->wide))
- adapter->ext_lun = true;
- /*
- Issue the Inquire PCI Host Adapter Information command to read the
- Termination Information from "W" series MultiMaster Host Adapters.
- */
- if (adapter->fw_ver[0] == '5') {
- if (blogic_cmd(adapter, BLOGIC_INQ_PCI_INFO, NULL, 0,
- &adapter_info,
- sizeof(adapter_info)) != sizeof(adapter_info))
- return blogic_failure(adapter,
- "INQUIRE PCI HOST ADAPTER INFORMATION");
- /*
- Save the Termination Information in the Host Adapter
- structure.
- */
- if (adapter_info.genericinfo_valid) {
- adapter->terminfo_valid = true;
- adapter->low_term = adapter_info.low_term;
- adapter->high_term = adapter_info.high_term;
- }
- }
- /*
- Issue the Fetch Host Adapter Local RAM command to read the
- AutoSCSI data from "W" and "C" series MultiMaster Host Adapters.
- */
- if (adapter->fw_ver[0] >= '4') {
- fetch_localram.offset = BLOGIC_AUTOSCSI_BASE;
- fetch_localram.count = sizeof(autoscsi);
- if (blogic_cmd(adapter, BLOGIC_FETCH_LOCALRAM, &fetch_localram,
- sizeof(fetch_localram), &autoscsi,
- sizeof(autoscsi)) != sizeof(autoscsi))
- return blogic_failure(adapter,
- "FETCH HOST ADAPTER LOCAL RAM");
- /*
- Save the Parity Checking Enabled, Bus Reset Enabled,
- and Termination Information in the Host Adapter structure.
- */
- adapter->parity = autoscsi.parity;
- adapter->reset_enabled = autoscsi.reset_enabled;
- if (adapter->fw_ver[0] == '4') {
- adapter->terminfo_valid = true;
- adapter->low_term = autoscsi.low_term;
- adapter->high_term = autoscsi.high_term;
- }
- /*
- Save the Wide Permitted, Fast Permitted, Synchronous
- Permitted, Disconnect Permitted, Ultra Permitted, and
- SCAM Information in the Host Adapter structure.
- */
- adapter->wide_ok = autoscsi.wide_ok;
- adapter->fast_ok = autoscsi.fast_ok;
- adapter->sync_ok = autoscsi.sync_ok;
- adapter->discon_ok = autoscsi.discon_ok;
- if (adapter->ultra)
- adapter->ultra_ok = autoscsi.ultra_ok;
- if (adapter->scam) {
- adapter->scam_enabled = autoscsi.scam_enabled;
- adapter->scam_lev2 = autoscsi.scam_lev2;
- }
- }
- /*
- Initialize fields in the Host Adapter structure for "S" and "A"
- series MultiMaster Host Adapters.
- */
- if (adapter->fw_ver[0] < '4') {
- if (setupinfo.sync) {
- adapter->sync_ok = 0xFF;
- if (adapter->adapter_bus_type == BLOGIC_EISA_BUS) {
- if (ext_setupinfo.misc.fast_on_eisa)
- adapter->fast_ok = 0xFF;
- if (strcmp(adapter->model, "BT-757") == 0)
- adapter->wide_ok = 0xFF;
- }
- }
- adapter->discon_ok = 0xFF;
- adapter->parity = setupinfo.parity;
- adapter->reset_enabled = true;
- }
- /*
- Determine the maximum number of Target IDs and Logical Units
- supported by this driver for Wide and Narrow Host Adapters.
- */
- adapter->maxdev = (adapter->wide ? 16 : 8);
- adapter->maxlun = (adapter->ext_lun ? 32 : 8);
- /*
- Select appropriate values for the Mailbox Count, Driver Queue Depth,
- Initial CCBs, and Incremental CCBs variables based on whether
- or not Strict Round Robin Mode is supported. If Strict Round
- Robin Mode is supported, then there is no performance degradation
- in using the maximum possible number of Outgoing and Incoming
- Mailboxes and allowing the Tagged and Untagged Queue Depths to
- determine the actual utilization. If Strict Round Robin Mode is
- not supported, then the Host Adapter must scan all the Outgoing
- Mailboxes whenever an Outgoing Mailbox entry is made, which can
- cause a substantial performance penalty. The host adapters
- actually have room to store the following number of CCBs
- internally; that is, they can internally queue and manage this
- many active commands on the SCSI bus simultaneously. Performance
- measurements demonstrate that the Driver Queue Depth should be
- set to the Mailbox Count, rather than the Host Adapter Queue
- Depth (internal CCB capacity), as it is more efficient to have the
- queued commands waiting in Outgoing Mailboxes if necessary than
- to block the process in the higher levels of the SCSI Subsystem.
- 192 BT-948/958/958D
- 100 BT-946C/956C/956CD/747C/757C/757CD/445C
- 50 BT-545C/540CF
- 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A
- */
- if (adapter->fw_ver[0] == '5')
- adapter->adapter_qdepth = 192;
- else if (adapter->fw_ver[0] == '4')
- adapter->adapter_qdepth = (adapter->adapter_bus_type !=
- BLOGIC_ISA_BUS ? 100 : 50);
- else
- adapter->adapter_qdepth = 30;
- if (strcmp(adapter->fw_ver, "3.31") >= 0) {
- adapter->strict_rr = true;
- adapter->mbox_count = BLOGIC_MAX_MAILBOX;
- } else {
- adapter->strict_rr = false;
- adapter->mbox_count = 32;
- }
- adapter->drvr_qdepth = adapter->mbox_count;
- adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE;
- adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE;
- /*
- Tagged Queuing support is available and operates properly on
- all "W" series MultiMaster Host Adapters, on "C" series
- MultiMaster Host Adapters with firmware version 4.22 and above,
- and on "S" series MultiMaster Host Adapters with firmware version
- 3.35 and above.
- */
- adapter->tagq_ok = 0;
- switch (adapter->fw_ver[0]) {
- case '5':
- adapter->tagq_ok = 0xFFFF;
- break;
- case '4':
- if (strcmp(adapter->fw_ver, "4.22") >= 0)
- adapter->tagq_ok = 0xFFFF;
- break;
- case '3':
- if (strcmp(adapter->fw_ver, "3.35") >= 0)
- adapter->tagq_ok = 0xFFFF;
- break;
- }
- /*
- Determine the Host Adapter BIOS Address if the BIOS is enabled and
- save it in the Host Adapter structure. The BIOS is disabled if the
- bios_addr is 0.
- */
- adapter->bios_addr = ext_setupinfo.bios_addr << 12;
- /*
- ISA Host Adapters require Bounce Buffers if there is more than
- 16MB memory.
- */
- if (adapter->adapter_bus_type == BLOGIC_ISA_BUS &&
- (void *) high_memory > (void *) MAX_DMA_ADDRESS)
- adapter->need_bouncebuf = true;
- /*
- BusLogic BT-445S Host Adapters prior to board revision E have a
- hardware bug whereby when the BIOS is enabled, transfers to/from
- the same address range the BIOS occupies modulo 16MB are handled
- incorrectly. Only properly functioning BT-445S Host Adapters
- have firmware version 3.37, so require that ISA Bounce Buffers
- be used for the buggy BT-445S models if there is more than 16MB
- memory.
- */
- if (adapter->bios_addr > 0 && strcmp(adapter->model, "BT-445S") == 0 &&
- strcmp(adapter->fw_ver, "3.37") < 0 &&
- (void *) high_memory > (void *) MAX_DMA_ADDRESS)
- adapter->need_bouncebuf = true;
- /*
- Initialize parameters common to MultiMaster and FlashPoint
- Host Adapters.
- */
- common:
- /*
- Initialize the Host Adapter Full Model Name from the Model Name.
- */
- strcpy(adapter->full_model, "BusLogic ");
- strcat(adapter->full_model, adapter->model);
- /*
- Select an appropriate value for the Tagged Queue Depth either from a
- BusLogic Driver Options specification, or based on whether this Host
- Adapter requires that ISA Bounce Buffers be used. The Tagged Queue
- Depth is left at 0 for automatic determination in
- BusLogic_SelectQueueDepths. Initialize the Untagged Queue Depth.
- */
- for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) {
- unsigned char qdepth = 0;
- if (adapter->drvr_opts != NULL &&
- adapter->drvr_opts->qdepth[tgt_id] > 0)
- qdepth = adapter->drvr_opts->qdepth[tgt_id];
- else if (adapter->need_bouncebuf)
- qdepth = BLOGIC_TAG_DEPTH_BB;
- adapter->qdepth[tgt_id] = qdepth;
- }
- if (adapter->need_bouncebuf)
- adapter->untag_qdepth = BLOGIC_UNTAG_DEPTH_BB;
- else
- adapter->untag_qdepth = BLOGIC_UNTAG_DEPTH;
- if (adapter->drvr_opts != NULL)
- adapter->common_qdepth = adapter->drvr_opts->common_qdepth;
- if (adapter->common_qdepth > 0 &&
- adapter->common_qdepth < adapter->untag_qdepth)
- adapter->untag_qdepth = adapter->common_qdepth;
- /*
- Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
- Therefore, mask the Tagged Queuing Permitted Default bits with the
- Disconnect/Reconnect Permitted bits.
- */
- adapter->tagq_ok &= adapter->discon_ok;
- /*
- Combine the default Tagged Queuing Permitted bits with any
- BusLogic Driver Options Tagged Queuing specification.
- */
- if (adapter->drvr_opts != NULL)
- adapter->tagq_ok = (adapter->drvr_opts->tagq_ok &
- adapter->drvr_opts->tagq_ok_mask) |
- (adapter->tagq_ok & ~adapter->drvr_opts->tagq_ok_mask);
- /*
- Select an appropriate value for Bus Settle Time either from a
- BusLogic Driver Options specification, or from
- BLOGIC_BUS_SETTLE_TIME.
- */
- if (adapter->drvr_opts != NULL &&
- adapter->drvr_opts->bus_settle_time > 0)
- adapter->bus_settle_time = adapter->drvr_opts->bus_settle_time;
- else
- adapter->bus_settle_time = BLOGIC_BUS_SETTLE_TIME;
- /*
- Indicate reading the Host Adapter Configuration completed
- successfully.
- */
- return true;
- }
- /*
- blogic_reportconfig reports the configuration of Host Adapter.
- */
- static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
- {
- unsigned short alltgt_mask = (1 << adapter->maxdev) - 1;
- unsigned short sync_ok, fast_ok;
- unsigned short ultra_ok, wide_ok;
- unsigned short discon_ok, tagq_ok;
- bool common_syncneg, common_tagq_depth;
- char syncstr[BLOGIC_MAXDEV + 1];
- char widestr[BLOGIC_MAXDEV + 1];
- char discon_str[BLOGIC_MAXDEV + 1];
- char tagq_str[BLOGIC_MAXDEV + 1];
- char *syncmsg = syncstr;
- char *widemsg = widestr;
- char *discon_msg = discon_str;
- char *tagq_msg = tagq_str;
- int tgt_id;
- blogic_info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", adapter, adapter->model, blogic_adapter_busnames[adapter->adapter_bus_type], (adapter->wide ? " Wide" : ""), (adapter->differential ? " Differential" : ""), (adapter->ultra ? " Ultra" : ""));
- blogic_info(" Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", adapter, adapter->fw_ver, adapter->io_addr, adapter->irq_ch, (adapter->level_int ? "Level" : "Edge"));
- if (adapter->adapter_bus_type != BLOGIC_PCI_BUS) {
- blogic_info(" DMA Channel: ", adapter);
- if (adapter->dma_ch > 0)
- blogic_info("%d, ", adapter, adapter->dma_ch);
- else
- blogic_info("None, ", adapter);
- if (adapter->bios_addr > 0)
- blogic_info("BIOS Address: 0x%X, ", adapter,
- adapter->bios_addr);
- else
- blogic_info("BIOS Address: None, ", adapter);
- } else {
- blogic_info(" PCI Bus: %d, Device: %d, Address: ", adapter,
- adapter->bus, adapter->dev);
- if (adapter->pci_addr > 0)
- blogic_info("0x%X, ", adapter, adapter->pci_addr);
- else
- blogic_info("Unassigned, ", adapter);
- }
- blogic_info("Host Adapter SCSI ID: %d\n", adapter, adapter->scsi_id);
- blogic_info(" Parity Checking: %s, Extended Translation: %s\n",
- adapter, (adapter->parity ? "Enabled" : "Disabled"),
- (adapter->ext_trans_enable ? "Enabled" : "Disabled"));
- alltgt_mask &= ~(1 << adapter->scsi_id);
- sync_ok = adapter->sync_ok & alltgt_mask;
- fast_ok = adapter->fast_ok & alltgt_mask;
- ultra_ok = adapter->ultra_ok & alltgt_mask;
- if ((blogic_multimaster_type(adapter) &&
- (adapter->fw_ver[0] >= '4' ||
- adapter->adapter_bus_type == BLOGIC_EISA_BUS)) ||
- blogic_flashpoint_type(adapter)) {
- common_syncneg = false;
- if (sync_ok == 0) {
- syncmsg = "Disabled";
- common_syncneg = true;
- } else if (sync_ok == alltgt_mask) {
- if (fast_ok == 0) {
- syncmsg = "Slow";
- common_syncneg = true;
- } else if (fast_ok == alltgt_mask) {
- if (ultra_ok == 0) {
- syncmsg = "Fast";
- common_syncneg = true;
- } else if (ultra_ok == alltgt_mask) {
- syncmsg = "Ultra";
- common_syncneg = true;
- }
- }
- }
- if (!common_syncneg) {
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- syncstr[tgt_id] = ((!(sync_ok & (1 << tgt_id))) ? 'N' : (!(fast_ok & (1 << tgt_id)) ? 'S' : (!(ultra_ok & (1 << tgt_id)) ? 'F' : 'U')));
- syncstr[adapter->scsi_id] = '#';
- syncstr[adapter->maxdev] = '\0';
- }
- } else
- syncmsg = (sync_ok == 0 ? "Disabled" : "Enabled");
- wide_ok = adapter->wide_ok & alltgt_mask;
- if (wide_ok == 0)
- widemsg = "Disabled";
- else if (wide_ok == alltgt_mask)
- widemsg = "Enabled";
- else {
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- widestr[tgt_id] = ((wide_ok & (1 << tgt_id)) ? 'Y' : 'N');
- widestr[adapter->scsi_id] = '#';
- widestr[adapter->maxdev] = '\0';
- }
- discon_ok = adapter->discon_ok & alltgt_mask;
- if (discon_ok == 0)
- discon_msg = "Disabled";
- else if (discon_ok == alltgt_mask)
- discon_msg = "Enabled";
- else {
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- discon_str[tgt_id] = ((discon_ok & (1 << tgt_id)) ? 'Y' : 'N');
- discon_str[adapter->scsi_id] = '#';
- discon_str[adapter->maxdev] = '\0';
- }
- tagq_ok = adapter->tagq_ok & alltgt_mask;
- if (tagq_ok == 0)
- tagq_msg = "Disabled";
- else if (tagq_ok == alltgt_mask)
- tagq_msg = "Enabled";
- else {
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- tagq_str[tgt_id] = ((tagq_ok & (1 << tgt_id)) ? 'Y' : 'N');
- tagq_str[adapter->scsi_id] = '#';
- tagq_str[adapter->maxdev] = '\0';
- }
- blogic_info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n",
- adapter, syncmsg, widemsg);
- blogic_info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", adapter,
- discon_msg, tagq_msg);
- if (blogic_multimaster_type(adapter)) {
- blogic_info(" Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", adapter, adapter->drvr_sglimit, adapter->adapter_sglimit, adapter->mbox_count);
- blogic_info(" Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", adapter, adapter->drvr_qdepth, adapter->adapter_qdepth);
- } else
- blogic_info(" Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", adapter, adapter->drvr_qdepth, adapter->drvr_sglimit);
- blogic_info(" Tagged Queue Depth: ", adapter);
- common_tagq_depth = true;
- for (tgt_id = 1; tgt_id < adapter->maxdev; tgt_id++)
- if (adapter->qdepth[tgt_id] != adapter->qdepth[0]) {
- common_tagq_depth = false;
- break;
- }
- if (common_tagq_depth) {
- if (adapter->qdepth[0] > 0)
- blogic_info("%d", adapter, adapter->qdepth[0]);
- else
- blogic_info("Automatic", adapter);
- } else
- blogic_info("Individual", adapter);
- blogic_info(", Untagged Queue Depth: %d\n", adapter,
- adapter->untag_qdepth);
- if (adapter->terminfo_valid) {
- if (adapter->wide)
- blogic_info(" SCSI Bus Termination: %s", adapter,
- (adapter->low_term ? (adapter->high_term ? "Both Enabled" : "Low Enabled") : (adapter->high_term ? "High Enabled" : "Both Disabled")));
- else
- blogic_info(" SCSI Bus Termination: %s", adapter,
- (adapter->low_term ? "Enabled" : "Disabled"));
- if (adapter->scam)
- blogic_info(", SCAM: %s", adapter,
- (adapter->scam_enabled ? (adapter->scam_lev2 ? "Enabled, Level 2" : "Enabled, Level 1") : "Disabled"));
- blogic_info("\n", adapter);
- }
- /*
- Indicate reporting the Host Adapter configuration completed
- successfully.
- */
- return true;
- }
- /*
- blogic_getres acquires the system resources necessary to use
- Host Adapter.
- */
- static bool __init blogic_getres(struct blogic_adapter *adapter)
- {
- if (adapter->irq_ch == 0) {
- blogic_err("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
- adapter);
- return false;
- }
- /*
- Acquire shared access to the IRQ Channel.
- */
- if (request_irq(adapter->irq_ch, blogic_inthandler, IRQF_SHARED,
- adapter->full_model, adapter) < 0) {
- blogic_err("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
- adapter, adapter->irq_ch);
- return false;
- }
- adapter->irq_acquired = true;
- /*
- Acquire exclusive access to the DMA Channel.
- */
- if (adapter->dma_ch > 0) {
- if (request_dma(adapter->dma_ch, adapter->full_model) < 0) {
- blogic_err("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", adapter, adapter->dma_ch);
- return false;
- }
- set_dma_mode(adapter->dma_ch, DMA_MODE_CASCADE);
- enable_dma(adapter->dma_ch);
- adapter->dma_chan_acquired = true;
- }
- /*
- Indicate the System Resource Acquisition completed successfully,
- */
- return true;
- }
- /*
- blogic_relres releases any system resources previously acquired
- by blogic_getres.
- */
- static void blogic_relres(struct blogic_adapter *adapter)
- {
- /*
- Release shared access to the IRQ Channel.
- */
- if (adapter->irq_acquired)
- free_irq(adapter->irq_ch, adapter);
- /*
- Release exclusive access to the DMA Channel.
- */
- if (adapter->dma_chan_acquired)
- free_dma(adapter->dma_ch);
- /*
- Release any allocated memory structs not released elsewhere
- */
- if (adapter->mbox_space)
- pci_free_consistent(adapter->pci_device, adapter->mbox_sz,
- adapter->mbox_space, adapter->mbox_space_handle);
- pci_dev_put(adapter->pci_device);
- adapter->mbox_space = NULL;
- adapter->mbox_space_handle = 0;
- adapter->mbox_sz = 0;
- }
- /*
- blogic_initadapter initializes Host Adapter. This is the only
- function called during SCSI Host Adapter detection which modifies the state
- of the Host Adapter from its initial power on or hard reset state.
- */
- static bool blogic_initadapter(struct blogic_adapter *adapter)
- {
- struct blogic_extmbox_req extmbox_req;
- enum blogic_rr_req rr_req;
- enum blogic_setccb_fmt setccb_fmt;
- int tgt_id;
- /*
- Initialize the pointers to the first and last CCBs that are
- queued for completion processing.
- */
- adapter->firstccb = NULL;
- adapter->lastccb = NULL;
- /*
- Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
- Command Successful Flag, Active Commands, and Commands Since Reset
- for each Target Device.
- */
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) {
- adapter->bdr_pend[tgt_id] = NULL;
- adapter->tgt_flags[tgt_id].tagq_active = false;
- adapter->tgt_flags[tgt_id].cmd_good = false;
- adapter->active_cmds[tgt_id] = 0;
- adapter->cmds_since_rst[tgt_id] = 0;
- }
- /*
- FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
- */
- if (blogic_flashpoint_type(adapter))
- goto done;
- /*
- Initialize the Outgoing and Incoming Mailbox pointers.
- */
- adapter->mbox_sz = adapter->mbox_count * (sizeof(struct blogic_outbox) + sizeof(struct blogic_inbox));
- adapter->mbox_space = pci_alloc_consistent(adapter->pci_device,
- adapter->mbox_sz, &adapter->mbox_space_handle);
- if (adapter->mbox_space == NULL)
- return blogic_failure(adapter, "MAILBOX ALLOCATION");
- adapter->first_outbox = (struct blogic_outbox *) adapter->mbox_space;
- adapter->last_outbox = adapter->first_outbox + adapter->mbox_count - 1;
- adapter->next_outbox = adapter->first_outbox;
- adapter->first_inbox = (struct blogic_inbox *) (adapter->last_outbox + 1);
- adapter->last_inbox = adapter->first_inbox + adapter->mbox_count - 1;
- adapter->next_inbox = adapter->first_inbox;
- /*
- Initialize the Outgoing and Incoming Mailbox structures.
- */
- memset(adapter->first_outbox, 0,
- adapter->mbox_count * sizeof(struct blogic_outbox));
- memset(adapter->first_inbox, 0,
- adapter->mbox_count * sizeof(struct blogic_inbox));
- /*
- Initialize the Host Adapter's Pointer to the Outgoing/Incoming
- Mailboxes.
- */
- extmbox_req.mbox_count = adapter->mbox_count;
- extmbox_req.base_mbox_addr = (u32) adapter->mbox_space_handle;
- if (blogic_cmd(adapter, BLOGIC_INIT_EXT_MBOX, &extmbox_req,
- sizeof(extmbox_req), NULL, 0) < 0)
- return blogic_failure(adapter, "MAILBOX INITIALIZATION");
- /*
- Enable Strict Round Robin Mode if supported by the Host Adapter. In
- Strict Round Robin Mode, the Host Adapter only looks at the next
- Outgoing Mailbox for each new command, rather than scanning
- through all the Outgoing Mailboxes to find any that have new
- commands in them. Strict Round Robin Mode is significantly more
- efficient.
- */
- if (adapter->strict_rr) {
- rr_req = BLOGIC_STRICT_RR_MODE;
- if (blogic_cmd(adapter, BLOGIC_STRICT_RR, &rr_req,
- sizeof(rr_req), NULL, 0) < 0)
- return blogic_failure(adapter,
- "ENABLE STRICT ROUND ROBIN MODE");
- }
- /*
- For Host Adapters that support Extended LUN Format CCBs, issue the
- Set CCB Format command to allow 32 Logical Units per Target Device.
- */
- if (adapter->ext_lun) {
- setccb_fmt = BLOGIC_EXT_LUN_CCB;
- if (blogic_cmd(adapter, BLOGIC_SETCCB_FMT, &setccb_fmt,
- sizeof(setccb_fmt), NULL, 0) < 0)
- return blogic_failure(adapter, "SET CCB FORMAT");
- }
- /*
- Announce Successful Initialization.
- */
- done:
- if (!adapter->adapter_initd) {
- blogic_info("*** %s Initialized Successfully ***\n", adapter,
- adapter->full_model);
- blogic_info("\n", adapter);
- } else
- blogic_warn("*** %s Initialized Successfully ***\n", adapter,
- adapter->full_model);
- adapter->adapter_initd = true;
- /*
- Indicate the Host Adapter Initialization completed successfully.
- */
- return true;
- }
- /*
- blogic_inquiry inquires about the Target Devices accessible
- through Host Adapter.
- */
- static bool __init blogic_inquiry(struct blogic_adapter *adapter)
- {
- u16 installed_devs;
- u8 installed_devs0to7[8];
- struct blogic_setup_info setupinfo;
- u8 sync_period[BLOGIC_MAXDEV];
- unsigned char req_replylen;
- int tgt_id;
- /*
- Wait a few seconds between the Host Adapter Hard Reset which
- initiates a SCSI Bus Reset and issuing any SCSI Commands. Some
- SCSI devices get confused if they receive SCSI Commands too soon
- after a SCSI Bus Reset.
- */
- blogic_delay(adapter->bus_settle_time);
- /*
- FlashPoint Host Adapters do not provide for Target Device Inquiry.
- */
- if (blogic_flashpoint_type(adapter))
- return true;
- /*
- Inhibit the Target Device Inquiry if requested.
- */
- if (adapter->drvr_opts != NULL && adapter->drvr_opts->stop_tgt_inquiry)
- return true;
- /*
- Issue the Inquire Target Devices command for host adapters with
- firmware version 4.25 or later, or the Inquire Installed Devices
- ID 0 to 7 command for older host adapters. This is necessary to
- force Synchronous Transfer Negotiation so that the Inquire Setup
- Information and Inquire Synchronous Period commands will return
- valid data. The Inquire Target Devices command is preferable to
- Inquire Installed Devices ID 0 to 7 since it only probes Logical
- Unit 0 of each Target Device.
- */
- if (strcmp(adapter->fw_ver, "4.25") >= 0) {
- /*
- Issue a Inquire Target Devices command. Inquire Target
- Devices only tests Logical Unit 0 of each Target Device
- unlike the Inquire Installed Devices commands which test
- Logical Units 0 - 7. Two bytes are returned, where byte
- 0 bit 0 set indicates that Target Device 0 exists, and so on.
- */
- if (blogic_cmd(adapter, BLOGIC_INQ_DEV, NULL, 0,
- &installed_devs, sizeof(installed_devs))
- != sizeof(installed_devs))
- return blogic_failure(adapter, "INQUIRE TARGET DEVICES");
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- adapter->tgt_flags[tgt_id].tgt_exists =
- (installed_devs & (1 << tgt_id) ? true : false);
- } else {
- /*
- Issue an Inquire Installed Devices command. For each
- Target Device, a byte is returned where bit 0 set
- indicates that Logical Unit 0 * exists, bit 1 set
- indicates that Logical Unit 1 exists, and so on.
- */
- if (blogic_cmd(adapter, BLOGIC_INQ_DEV0TO7, NULL, 0,
- &installed_devs0to7, sizeof(installed_devs0to7))
- != sizeof(installed_devs0to7))
- return blogic_failure(adapter,
- "INQUIRE INSTALLED DEVICES ID 0 TO 7");
- for (tgt_id = 0; tgt_id < 8; tgt_id++)
- adapter->tgt_flags[tgt_id].tgt_exists =
- (installed_devs0to7[tgt_id] != 0 ? true : false);
- }
- /*
- Issue the Inquire Setup Information command.
- */
- req_replylen = sizeof(setupinfo);
- if (blogic_cmd(adapter, BLOGIC_INQ_SETUPINFO, &req_replylen,
- sizeof(req_replylen), &setupinfo, sizeof(setupinfo))
- != sizeof(setupinfo))
- return blogic_failure(adapter, "INQUIRE SETUP INFORMATION");
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- adapter->sync_offset[tgt_id] = (tgt_id < 8 ? setupinfo.sync0to7[tgt_id].offset : setupinfo.sync8to15[tgt_id - 8].offset);
- if (strcmp(adapter->fw_ver, "5.06L") >= 0)
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- adapter->tgt_flags[tgt_id].wide_active = (tgt_id < 8 ? (setupinfo.wide_tx_active0to7 & (1 << tgt_id) ? true : false) : (setupinfo.wide_tx_active8to15 & (1 << (tgt_id - 8)) ? true : false));
- /*
- Issue the Inquire Synchronous Period command.
- */
- if (adapter->fw_ver[0] >= '3') {
- /* Issue a Inquire Synchronous Period command. For each
- Target Device, a byte is returned which represents the
- Synchronous Transfer Period in units of 10 nanoseconds.
- */
- req_replylen = sizeof(sync_period);
- if (blogic_cmd(adapter, BLOGIC_INQ_SYNC_PERIOD, &req_replylen,
- sizeof(req_replylen), &sync_period,
- sizeof(sync_period)) != sizeof(sync_period))
- return blogic_failure(adapter,
- "INQUIRE SYNCHRONOUS PERIOD");
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- adapter->sync_period[tgt_id] = sync_period[tgt_id];
- } else
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- if (setupinfo.sync0to7[tgt_id].offset > 0)
- adapter->sync_period[tgt_id] = 20 + 5 * setupinfo.sync0to7[tgt_id].tx_period;
- /*
- Indicate the Target Device Inquiry completed successfully.
- */
- return true;
- }
- /*
- blogic_inithoststruct initializes the fields in the SCSI Host
- structure. The base, io_port, n_io_ports, irq, and dma_channel fields in the
- SCSI Host structure are intentionally left uninitialized, as this driver
- handles acquisition and release of these resources explicitly, as well as
- ensuring exclusive access to the Host Adapter hardware and data structures
- through explicit acquisition and release of the Host Adapter's Lock.
- */
- static void __init blogic_inithoststruct(struct blogic_adapter *adapter,
- struct Scsi_Host *host)
- {
- host->max_id = adapter->maxdev;
- host->max_lun = adapter->maxlun;
- host->max_channel = 0;
- host->unique_id = adapter->io_addr;
- host->this_id = adapter->scsi_id;
- host->can_queue = adapter->drvr_qdepth;
- host->sg_tablesize = adapter->drvr_sglimit;
- host->unchecked_isa_dma = adapter->need_bouncebuf;
- host->cmd_per_lun = adapter->untag_qdepth;
- }
- /*
- blogic_slaveconfig will actually set the queue depth on individual
- scsi devices as they are permanently added to the device chain. We
- shamelessly rip off the SelectQueueDepths code to make this work mostly
- like it used to. Since we don't get called once at the end of the scan
- but instead get called for each device, we have to do things a bit
- differently.
- */
- static int blogic_slaveconfig(struct scsi_device *dev)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) dev->host->hostdata;
- int tgt_id = dev->id;
- int qdepth = adapter->qdepth[tgt_id];
- if (adapter->tgt_flags[tgt_id].tagq_ok &&
- (adapter->tagq_ok & (1 << tgt_id))) {
- if (qdepth == 0)
- qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH;
- adapter->qdepth[tgt_id] = qdepth;
- scsi_change_queue_depth(dev, qdepth);
- } else {
- adapter->tagq_ok &= ~(1 << tgt_id);
- qdepth = adapter->untag_qdepth;
- adapter->qdepth[tgt_id] = qdepth;
- scsi_change_queue_depth(dev, qdepth);
- }
- qdepth = 0;
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
- if (adapter->tgt_flags[tgt_id].tgt_exists)
- qdepth += adapter->qdepth[tgt_id];
- if (qdepth > adapter->alloc_ccbs)
- blogic_create_addlccbs(adapter, qdepth - adapter->alloc_ccbs,
- false);
- return 0;
- }
- /*
- blogic_init probes for BusLogic Host Adapters at the standard
- I/O Addresses where they may be located, initializing, registering, and
- reporting the configuration of each BusLogic Host Adapter it finds. It
- returns the number of BusLogic Host Adapters successfully initialized and
- registered.
- */
- static int __init blogic_init(void)
- {
- int adapter_count = 0, drvr_optindex = 0, probeindex;
- struct blogic_adapter *adapter;
- int ret = 0;
- #ifdef MODULE
- if (BusLogic)
- blogic_setup(BusLogic);
- #endif
- if (blogic_probe_options.noprobe)
- return -ENODEV;
- blogic_probeinfo_list =
- kzalloc(BLOGIC_MAX_ADAPTERS * sizeof(struct blogic_probeinfo),
- GFP_KERNEL);
- if (blogic_probeinfo_list == NULL) {
- blogic_err("BusLogic: Unable to allocate Probe Info List\n",
- NULL);
- return -ENOMEM;
- }
- adapter = kzalloc(sizeof(struct blogic_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- kfree(blogic_probeinfo_list);
- blogic_err("BusLogic: Unable to allocate Prototype Host Adapter\n", NULL);
- return -ENOMEM;
- }
- #ifdef MODULE
- if (BusLogic != NULL)
- blogic_setup(BusLogic);
- #endif
- blogic_init_probeinfo_list(adapter);
- for (probeindex = 0; probeindex < blogic_probeinfo_count; probeindex++) {
- struct blogic_probeinfo *probeinfo =
- &blogic_probeinfo_list[probeindex];
- struct blogic_adapter *myadapter = adapter;
- struct Scsi_Host *host;
- if (probeinfo->io_addr == 0)
- continue;
- memset(myadapter, 0, sizeof(struct blogic_adapter));
- myadapter->adapter_type = probeinfo->adapter_type;
- myadapter->adapter_bus_type = probeinfo->adapter_bus_type;
- myadapter->io_addr = probeinfo->io_addr;
- myadapter->pci_addr = probeinfo->pci_addr;
- myadapter->bus = probeinfo->bus;
- myadapter->dev = probeinfo->dev;
- myadapter->pci_device = probeinfo->pci_device;
- myadapter->irq_ch = probeinfo->irq_ch;
- myadapter->addr_count =
- blogic_adapter_addr_count[myadapter->adapter_type];
- /*
- Make sure region is free prior to probing.
- */
- if (!request_region(myadapter->io_addr, myadapter->addr_count,
- "BusLogic"))
- continue;
- /*
- Probe the Host Adapter. If unsuccessful, abort further
- initialization.
- */
- if (!blogic_probe(myadapter)) {
- release_region(myadapter->io_addr,
- myadapter->addr_count);
- continue;
- }
- /*
- Hard Reset the Host Adapter. If unsuccessful, abort further
- initialization.
- */
- if (!blogic_hwreset(myadapter, true)) {
- release_region(myadapter->io_addr,
- myadapter->addr_count);
- continue;
- }
- /*
- Check the Host Adapter. If unsuccessful, abort further
- initialization.
- */
- if (!blogic_checkadapter(myadapter)) {
- release_region(myadapter->io_addr,
- myadapter->addr_count);
- continue;
- }
- /*
- Initialize the Driver Options field if provided.
- */
- if (drvr_optindex < blogic_drvr_options_count)
- myadapter->drvr_opts =
- &blogic_drvr_options[drvr_optindex++];
- /*
- Announce the Driver Version and Date, Author's Name,
- Copyright Notice, and Electronic Mail Address.
- */
- blogic_announce_drvr(myadapter);
- /*
- Register the SCSI Host structure.
- */
- host = scsi_host_alloc(&blogic_template,
- sizeof(struct blogic_adapter));
- if (host == NULL) {
- release_region(myadapter->io_addr,
- myadapter->addr_count);
- continue;
- }
- myadapter = (struct blogic_adapter *) host->hostdata;
- memcpy(myadapter, adapter, sizeof(struct blogic_adapter));
- myadapter->scsi_host = host;
- myadapter->host_no = host->host_no;
- /*
- Add Host Adapter to the end of the list of registered
- BusLogic Host Adapters.
- */
- list_add_tail(&myadapter->host_list, &blogic_host_list);
- /*
- Read the Host Adapter Configuration, Configure the Host
- Adapter, Acquire the System Resources necessary to use
- the Host Adapter, then Create the Initial CCBs, Initialize
- the Host Adapter, and finally perform Target Device
- Inquiry. From this point onward, any failure will be
- assumed to be due to a problem with the Host Adapter,
- rather than due to having mistakenly identified this port
- as belonging to a BusLogic Host Adapter. The I/O Address
- range will not be released, thereby preventing it from
- being incorrectly identified as any other type of Host
- Adapter.
- */
- if (blogic_rdconfig(myadapter) &&
- blogic_reportconfig(myadapter) &&
- blogic_getres(myadapter) &&
- blogic_create_initccbs(myadapter) &&
- blogic_initadapter(myadapter) &&
- blogic_inquiry(myadapter)) {
- /*
- Initialization has been completed successfully.
- Release and re-register usage of the I/O Address
- range so that the Model Name of the Host Adapter
- will appear, and initialize the SCSI Host structure.
- */
- release_region(myadapter->io_addr,
- myadapter->addr_count);
- if (!request_region(myadapter->io_addr,
- myadapter->addr_count,
- myadapter->full_model)) {
- printk(KERN_WARNING
- "BusLogic: Release and re-register of "
- "port 0x%04lx failed \n",
- (unsigned long)myadapter->io_addr);
- blogic_destroy_ccbs(myadapter);
- blogic_relres(myadapter);
- list_del(&myadapter->host_list);
- scsi_host_put(host);
- ret = -ENOMEM;
- } else {
- blogic_inithoststruct(myadapter,
- host);
- if (scsi_add_host(host, myadapter->pci_device
- ? &myadapter->pci_device->dev
- : NULL)) {
- printk(KERN_WARNING
- "BusLogic: scsi_add_host()"
- "failed!\n");
- blogic_destroy_ccbs(myadapter);
- blogic_relres(myadapter);
- list_del(&myadapter->host_list);
- scsi_host_put(host);
- ret = -ENODEV;
- } else {
- scsi_scan_host(host);
- adapter_count++;
- }
- }
- } else {
- /*
- An error occurred during Host Adapter Configuration
- Querying, Host Adapter Configuration, Resource
- Acquisition, CCB Creation, Host Adapter
- Initialization, or Target Device Inquiry, so
- remove Host Adapter from the list of registered
- BusLogic Host Adapters, destroy the CCBs, Release
- the System Resources, and Unregister the SCSI
- Host.
- */
- blogic_destroy_ccbs(myadapter);
- blogic_relres(myadapter);
- list_del(&myadapter->host_list);
- scsi_host_put(host);
- ret = -ENODEV;
- }
- }
- kfree(adapter);
- kfree(blogic_probeinfo_list);
- blogic_probeinfo_list = NULL;
- return ret;
- }
- /*
- blogic_deladapter releases all resources previously acquired to
- support a specific Host Adapter, including the I/O Address range, and
- unregisters the BusLogic Host Adapter.
- */
- static int __exit blogic_deladapter(struct blogic_adapter *adapter)
- {
- struct Scsi_Host *host = adapter->scsi_host;
- scsi_remove_host(host);
- /*
- FlashPoint Host Adapters must first be released by the FlashPoint
- SCCB Manager.
- */
- if (blogic_flashpoint_type(adapter))
- FlashPoint_ReleaseHostAdapter(adapter->cardhandle);
- /*
- Destroy the CCBs and release any system resources acquired to
- support Host Adapter.
- */
- blogic_destroy_ccbs(adapter);
- blogic_relres(adapter);
- /*
- Release usage of the I/O Address range.
- */
- release_region(adapter->io_addr, adapter->addr_count);
- /*
- Remove Host Adapter from the list of registered BusLogic
- Host Adapters.
- */
- list_del(&adapter->host_list);
- scsi_host_put(host);
- return 0;
- }
- /*
- blogic_qcompleted_ccb queues CCB for completion processing.
- */
- static void blogic_qcompleted_ccb(struct blogic_ccb *ccb)
- {
- struct blogic_adapter *adapter = ccb->adapter;
- ccb->status = BLOGIC_CCB_COMPLETE;
- ccb->next = NULL;
- if (adapter->firstccb == NULL) {
- adapter->firstccb = ccb;
- adapter->lastccb = ccb;
- } else {
- adapter->lastccb->next = ccb;
- adapter->lastccb = ccb;
- }
- adapter->active_cmds[ccb->tgt_id]--;
- }
- /*
- blogic_resultcode computes a SCSI Subsystem Result Code from
- the Host Adapter Status and Target Device Status.
- */
- static int blogic_resultcode(struct blogic_adapter *adapter,
- enum blogic_adapter_status adapter_status,
- enum blogic_tgt_status tgt_status)
- {
- int hoststatus;
- switch (adapter_status) {
- case BLOGIC_CMD_CMPLT_NORMAL:
- case BLOGIC_LINK_CMD_CMPLT:
- case BLOGIC_LINK_CMD_CMPLT_FLAG:
- hoststatus = DID_OK;
- break;
- case BLOGIC_SELECT_TIMEOUT:
- hoststatus = DID_TIME_OUT;
- break;
- case BLOGIC_INVALID_OUTBOX_CODE:
- case BLOGIC_INVALID_CMD_CODE:
- case BLOGIC_BAD_CMD_PARAM:
- blogic_warn("BusLogic Driver Protocol Error 0x%02X\n",
- adapter, adapter_status);
- case BLOGIC_DATA_UNDERRUN:
- case BLOGIC_DATA_OVERRUN:
- case BLOGIC_NOEXPECT_BUSFREE:
- case BLOGIC_LINKCCB_BADLUN:
- case BLOGIC_AUTOREQSENSE_FAIL:
- case BLOGIC_TAGQUEUE_REJECT:
- case BLOGIC_BAD_MSG_RCVD:
- case BLOGIC_HW_FAIL:
- case BLOGIC_BAD_RECONNECT:
- case BLOGIC_ABRT_QUEUE:
- case BLOGIC_ADAPTER_SW_ERROR:
- case BLOGIC_HW_TIMEOUT:
- case BLOGIC_PARITY_ERR:
- hoststatus = DID_ERROR;
- break;
- case BLOGIC_INVALID_BUSPHASE:
- case BLOGIC_NORESPONSE_TO_ATN:
- case BLOGIC_HW_RESET:
- case BLOGIC_RST_FROM_OTHERDEV:
- case BLOGIC_HW_BDR:
- hoststatus = DID_RESET;
- break;
- default:
- blogic_warn("Unknown Host Adapter Status 0x%02X\n", adapter,
- adapter_status);
- hoststatus = DID_ERROR;
- break;
- }
- return (hoststatus << 16) | tgt_status;
- }
- /*
- blogic_scan_inbox scans the Incoming Mailboxes saving any
- Incoming Mailbox entries for completion processing.
- */
- static void blogic_scan_inbox(struct blogic_adapter *adapter)
- {
- /*
- Scan through the Incoming Mailboxes in Strict Round Robin
- fashion, saving any completed CCBs for further processing. It
- is essential that for each CCB and SCSI Command issued, command
- completion processing is performed exactly once. Therefore,
- only Incoming Mailboxes with completion code Command Completed
- Without Error, Command Completed With Error, or Command Aborted
- At Host Request are saved for completion processing. When an
- Incoming Mailbox has a completion code of Aborted Command Not
- Found, the CCB had already completed or been aborted before the
- current Abort request was processed, and so completion processing
- has already occurred and no further action should be taken.
- */
- struct blogic_inbox *next_inbox = adapter->next_inbox;
- enum blogic_cmplt_code comp_code;
- while ((comp_code = next_inbox->comp_code) != BLOGIC_INBOX_FREE) {
- /*
- We are only allowed to do this because we limit our
- architectures we run on to machines where bus_to_virt(
- actually works. There *needs* to be a dma_addr_to_virt()
- in the new PCI DMA mapping interface to replace
- bus_to_virt() or else this code is going to become very
- innefficient.
- */
- struct blogic_ccb *ccb =
- (struct blogic_ccb *) bus_to_virt(next_inbox->ccb);
- if (comp_code != BLOGIC_CMD_NOTFOUND) {
- if (ccb->status == BLOGIC_CCB_ACTIVE ||
- ccb->status == BLOGIC_CCB_RESET) {
- /*
- Save the Completion Code for this CCB and
- queue the CCB for completion processing.
- */
- ccb->comp_code = comp_code;
- blogic_qcompleted_ccb(ccb);
- } else {
- /*
- If a CCB ever appears in an Incoming Mailbox
- and is not marked as status Active or Reset,
- then there is most likely a bug in
- the Host Adapter firmware.
- */
- blogic_warn("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", adapter, ccb->serial, ccb->status);
- }
- }
- next_inbox->comp_code = BLOGIC_INBOX_FREE;
- if (++next_inbox > adapter->last_inbox)
- next_inbox = adapter->first_inbox;
- }
- adapter->next_inbox = next_inbox;
- }
- /*
- blogic_process_ccbs iterates over the completed CCBs for Host
- Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
- calling the SCSI Subsystem Completion Routines. The Host Adapter's Lock
- should already have been acquired by the caller.
- */
- static void blogic_process_ccbs(struct blogic_adapter *adapter)
- {
- if (adapter->processing_ccbs)
- return;
- adapter->processing_ccbs = true;
- while (adapter->firstccb != NULL) {
- struct blogic_ccb *ccb = adapter->firstccb;
- struct scsi_cmnd *command = ccb->command;
- adapter->firstccb = ccb->next;
- if (adapter->firstccb == NULL)
- adapter->lastccb = NULL;
- /*
- Process the Completed CCB.
- */
- if (ccb->opcode == BLOGIC_BDR) {
- int tgt_id = ccb->tgt_id;
- blogic_warn("Bus Device Reset CCB #%ld to Target " "%d Completed\n", adapter, ccb->serial, tgt_id);
- blogic_inc_count(&adapter->tgt_stats[tgt_id].bdr_done);
- adapter->tgt_flags[tgt_id].tagq_active = false;
- adapter->cmds_since_rst[tgt_id] = 0;
- adapter->last_resetdone[tgt_id] = jiffies;
- /*
- Place CCB back on the Host Adapter's free list.
- */
- blogic_dealloc_ccb(ccb, 1);
- #if 0 /* this needs to be redone different for new EH */
- /*
- Bus Device Reset CCBs have the command field
- non-NULL only when a Bus Device Reset was requested
- for a command that did not have a currently active
- CCB in the Host Adapter (i.e., a Synchronous Bus
- Device Reset), and hence would not have its
- Completion Routine called otherwise.
- */
- while (command != NULL) {
- struct scsi_cmnd *nxt_cmd =
- command->reset_chain;
- command->reset_chain = NULL;
- command->result = DID_RESET << 16;
- command->scsi_done(command);
- command = nxt_cmd;
- }
- #endif
- /*
- Iterate over the CCBs for this Host Adapter
- performing completion processing for any CCBs
- marked as Reset for this Target.
- */
- for (ccb = adapter->all_ccbs; ccb != NULL;
- ccb = ccb->next_all)
- if (ccb->status == BLOGIC_CCB_RESET &&
- ccb->tgt_id == tgt_id) {
- command = ccb->command;
- blogic_dealloc_ccb(ccb, 1);
- adapter->active_cmds[tgt_id]--;
- command->result = DID_RESET << 16;
- command->scsi_done(command);
- }
- adapter->bdr_pend[tgt_id] = NULL;
- } else {
- /*
- Translate the Completion Code, Host Adapter Status,
- and Target Device Status into a SCSI Subsystem
- Result Code.
- */
- switch (ccb->comp_code) {
- case BLOGIC_INBOX_FREE:
- case BLOGIC_CMD_NOTFOUND:
- case BLOGIC_INVALID_CCB:
- blogic_warn("CCB #%ld to Target %d Impossible State\n", adapter, ccb->serial, ccb->tgt_id);
- break;
- case BLOGIC_CMD_COMPLETE_GOOD:
- adapter->tgt_stats[ccb->tgt_id]
- .cmds_complete++;
- adapter->tgt_flags[ccb->tgt_id]
- .cmd_good = true;
- command->result = DID_OK << 16;
- break;
- case BLOGIC_CMD_ABORT_BY_HOST:
- blogic_warn("CCB #%ld to Target %d Aborted\n",
- adapter, ccb->serial, ccb->tgt_id);
- blogic_inc_count(&adapter->tgt_stats[ccb->tgt_id].aborts_done);
- command->result = DID_ABORT << 16;
- break;
- case BLOGIC_CMD_COMPLETE_ERROR:
- command->result = blogic_resultcode(adapter,
- ccb->adapter_status, ccb->tgt_status);
- if (ccb->adapter_status != BLOGIC_SELECT_TIMEOUT) {
- adapter->tgt_stats[ccb->tgt_id]
- .cmds_complete++;
- if (blogic_global_options.trace_err) {
- int i;
- blogic_notice("CCB #%ld Target %d: Result %X Host "
- "Adapter Status %02X " "Target Status %02X\n", adapter, ccb->serial, ccb->tgt_id, command->result, ccb->adapter_status, ccb->tgt_status);
- blogic_notice("CDB ", adapter);
- for (i = 0; i < ccb->cdblen; i++)
- blogic_notice(" %02X", adapter, ccb->cdb[i]);
- blogic_notice("\n", adapter);
- blogic_notice("Sense ", adapter);
- for (i = 0; i < ccb->sense_datalen; i++)
- blogic_notice(" %02X", adapter, command->sense_buffer[i]);
- blogic_notice("\n", adapter);
- }
- }
- break;
- }
- /*
- When an INQUIRY command completes normally, save the
- CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit
- Wide Data Transfers Supported) bits.
- */
- if (ccb->cdb[0] == INQUIRY && ccb->cdb[1] == 0 &&
- ccb->adapter_status == BLOGIC_CMD_CMPLT_NORMAL) {
- struct blogic_tgt_flags *tgt_flags =
- &adapter->tgt_flags[ccb->tgt_id];
- struct scsi_inquiry *inquiry =
- (struct scsi_inquiry *) scsi_sglist(command);
- tgt_flags->tgt_exists = true;
- tgt_flags->tagq_ok = inquiry->CmdQue;
- tgt_flags->wide_ok = inquiry->WBus16;
- }
- /*
- Place CCB back on the Host Adapter's free list.
- */
- blogic_dealloc_ccb(ccb, 1);
- /*
- Call the SCSI Command Completion Routine.
- */
- command->scsi_done(command);
- }
- }
- adapter->processing_ccbs = false;
- }
- /*
- blogic_inthandler handles hardware interrupts from BusLogic Host
- Adapters.
- */
- static irqreturn_t blogic_inthandler(int irq_ch, void *devid)
- {
- struct blogic_adapter *adapter = (struct blogic_adapter *) devid;
- unsigned long processor_flag;
- /*
- Acquire exclusive access to Host Adapter.
- */
- spin_lock_irqsave(adapter->scsi_host->host_lock, processor_flag);
- /*
- Handle Interrupts appropriately for each Host Adapter type.
- */
- if (blogic_multimaster_type(adapter)) {
- union blogic_int_reg intreg;
- /*
- Read the Host Adapter Interrupt Register.
- */
- intreg.all = blogic_rdint(adapter);
- if (intreg.ir.int_valid) {
- /*
- Acknowledge the interrupt and reset the Host Adapter
- Interrupt Register.
- */
- blogic_intreset(adapter);
- /*
- Process valid External SCSI Bus Reset and Incoming
- Mailbox Loaded Interrupts. Command Complete
- Interrupts are noted, and Outgoing Mailbox Available
- Interrupts are ignored, as they are never enabled.
- */
- if (intreg.ir.ext_busreset)
- adapter->adapter_extreset = true;
- else if (intreg.ir.mailin_loaded)
- blogic_scan_inbox(adapter);
- else if (intreg.ir.cmd_complete)
- adapter->adapter_cmd_complete = true;
- }
- } else {
- /*
- Check if there is a pending interrupt for this Host Adapter.
- */
- if (FlashPoint_InterruptPending(adapter->cardhandle))
- switch (FlashPoint_HandleInterrupt(adapter->cardhandle)) {
- case FPOINT_NORMAL_INT:
- break;
- case FPOINT_EXT_RESET:
- adapter->adapter_extreset = true;
- break;
- case FPOINT_INTERN_ERR:
- blogic_warn("Internal FlashPoint Error detected - Resetting Host Adapter\n", adapter);
- adapter->adapter_intern_err = true;
- break;
- }
- }
- /*
- Process any completed CCBs.
- */
- if (adapter->firstccb != NULL)
- blogic_process_ccbs(adapter);
- /*
- Reset the Host Adapter if requested.
- */
- if (adapter->adapter_extreset) {
- blogic_warn("Resetting %s due to External SCSI Bus Reset\n", adapter, adapter->full_model);
- blogic_inc_count(&adapter->ext_resets);
- blogic_resetadapter(adapter, false);
- adapter->adapter_extreset = false;
- } else if (adapter->adapter_intern_err) {
- blogic_warn("Resetting %s due to Host Adapter Internal Error\n", adapter, adapter->full_model);
- blogic_inc_count(&adapter->adapter_intern_errors);
- blogic_resetadapter(adapter, true);
- adapter->adapter_intern_err = false;
- }
- /*
- Release exclusive access to Host Adapter.
- */
- spin_unlock_irqrestore(adapter->scsi_host->host_lock, processor_flag);
- return IRQ_HANDLED;
- }
- /*
- blogic_write_outbox places CCB and Action Code into an Outgoing
- Mailbox for execution by Host Adapter. The Host Adapter's Lock should
- already have been acquired by the caller.
- */
- static bool blogic_write_outbox(struct blogic_adapter *adapter,
- enum blogic_action action, struct blogic_ccb *ccb)
- {
- struct blogic_outbox *next_outbox;
- next_outbox = adapter->next_outbox;
- if (next_outbox->action == BLOGIC_OUTBOX_FREE) {
- ccb->status = BLOGIC_CCB_ACTIVE;
- /*
- The CCB field must be written before the Action Code field
- since the Host Adapter is operating asynchronously and the
- locking code does not protect against simultaneous access
- by the Host Adapter.
- */
- next_outbox->ccb = ccb->dma_handle;
- next_outbox->action = action;
- blogic_execmbox(adapter);
- if (++next_outbox > adapter->last_outbox)
- next_outbox = adapter->first_outbox;
- adapter->next_outbox = next_outbox;
- if (action == BLOGIC_MBOX_START) {
- adapter->active_cmds[ccb->tgt_id]++;
- if (ccb->opcode != BLOGIC_BDR)
- adapter->tgt_stats[ccb->tgt_id].cmds_tried++;
- }
- return true;
- }
- return false;
- }
- /* Error Handling (EH) support */
- static int blogic_hostreset(struct scsi_cmnd *SCpnt)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) SCpnt->device->host->hostdata;
- unsigned int id = SCpnt->device->id;
- struct blogic_tgt_stats *stats = &adapter->tgt_stats[id];
- int rc;
- spin_lock_irq(SCpnt->device->host->host_lock);
- blogic_inc_count(&stats->adatper_reset_req);
- rc = blogic_resetadapter(adapter, false);
- spin_unlock_irq(SCpnt->device->host->host_lock);
- return rc;
- }
- /*
- blogic_qcmd creates a CCB for Command and places it into an
- Outgoing Mailbox for execution by the associated Host Adapter.
- */
- static int blogic_qcmd_lck(struct scsi_cmnd *command,
- void (*comp_cb) (struct scsi_cmnd *))
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) command->device->host->hostdata;
- struct blogic_tgt_flags *tgt_flags =
- &adapter->tgt_flags[command->device->id];
- struct blogic_tgt_stats *tgt_stats = adapter->tgt_stats;
- unsigned char *cdb = command->cmnd;
- int cdblen = command->cmd_len;
- int tgt_id = command->device->id;
- int lun = command->device->lun;
- int buflen = scsi_bufflen(command);
- int count;
- struct blogic_ccb *ccb;
- dma_addr_t sense_buf;
- /*
- SCSI REQUEST_SENSE commands will be executed automatically by the
- Host Adapter for any errors, so they should not be executed
- explicitly unless the Sense Data is zero indicating that no error
- occurred.
- */
- if (cdb[0] == REQUEST_SENSE && command->sense_buffer[0] != 0) {
- command->result = DID_OK << 16;
- comp_cb(command);
- return 0;
- }
- /*
- Allocate a CCB from the Host Adapter's free list. In the unlikely
- event that there are none available and memory allocation fails,
- wait 1 second and try again. If that fails, the Host Adapter is
- probably hung so signal an error as a Host Adapter Hard Reset
- should be initiated soon.
- */
- ccb = blogic_alloc_ccb(adapter);
- if (ccb == NULL) {
- spin_unlock_irq(adapter->scsi_host->host_lock);
- blogic_delay(1);
- spin_lock_irq(adapter->scsi_host->host_lock);
- ccb = blogic_alloc_ccb(adapter);
- if (ccb == NULL) {
- command->result = DID_ERROR << 16;
- comp_cb(command);
- return 0;
- }
- }
- /*
- Initialize the fields in the BusLogic Command Control Block (CCB).
- */
- count = scsi_dma_map(command);
- BUG_ON(count < 0);
- if (count) {
- struct scatterlist *sg;
- int i;
- ccb->opcode = BLOGIC_INITIATOR_CCB_SG;
- ccb->datalen = count * sizeof(struct blogic_sg_seg);
- if (blogic_multimaster_type(adapter))
- ccb->data = (void *)((unsigned int) ccb->dma_handle +
- ((unsigned long) &ccb->sglist -
- (unsigned long) ccb));
- else
- ccb->data = ccb->sglist;
- scsi_for_each_sg(command, sg, count, i) {
- ccb->sglist[i].segbytes = sg_dma_len(sg);
- ccb->sglist[i].segdata = sg_dma_address(sg);
- }
- } else if (!count) {
- ccb->opcode = BLOGIC_INITIATOR_CCB;
- ccb->datalen = buflen;
- ccb->data = 0;
- }
- switch (cdb[0]) {
- case READ_6:
- case READ_10:
- ccb->datadir = BLOGIC_DATAIN_CHECKED;
- tgt_stats[tgt_id].read_cmds++;
- blogic_addcount(&tgt_stats[tgt_id].bytesread, buflen);
- blogic_incszbucket(tgt_stats[tgt_id].read_sz_buckets, buflen);
- break;
- case WRITE_6:
- case WRITE_10:
- ccb->datadir = BLOGIC_DATAOUT_CHECKED;
- tgt_stats[tgt_id].write_cmds++;
- blogic_addcount(&tgt_stats[tgt_id].byteswritten, buflen);
- blogic_incszbucket(tgt_stats[tgt_id].write_sz_buckets, buflen);
- break;
- default:
- ccb->datadir = BLOGIC_UNCHECKED_TX;
- break;
- }
- ccb->cdblen = cdblen;
- ccb->adapter_status = 0;
- ccb->tgt_status = 0;
- ccb->tgt_id = tgt_id;
- ccb->lun = lun;
- ccb->tag_enable = false;
- ccb->legacytag_enable = false;
- /*
- BusLogic recommends that after a Reset the first couple of
- commands that are sent to a Target Device be sent in a non
- Tagged Queue fashion so that the Host Adapter and Target Device
- can establish Synchronous and Wide Transfer before Queue Tag
- messages can interfere with the Synchronous and Wide Negotiation
- messages. By waiting to enable Tagged Queuing until after the
- first BLOGIC_MAX_TAG_DEPTH commands have been queued, it is
- assured that after a Reset any pending commands are requeued
- before Tagged Queuing is enabled and that the Tagged Queuing
- message will not occur while the partition table is being printed.
- In addition, some devices do not properly handle the transition
- from non-tagged to tagged commands, so it is necessary to wait
- until there are no pending commands for a target device
- before queuing tagged commands.
- */
- if (adapter->cmds_since_rst[tgt_id]++ >= BLOGIC_MAX_TAG_DEPTH &&
- !tgt_flags->tagq_active &&
- adapter->active_cmds[tgt_id] == 0
- && tgt_flags->tagq_ok &&
- (adapter->tagq_ok & (1 << tgt_id))) {
- tgt_flags->tagq_active = true;
- blogic_notice("Tagged Queuing now active for Target %d\n",
- adapter, tgt_id);
- }
- if (tgt_flags->tagq_active) {
- enum blogic_queuetag queuetag = BLOGIC_SIMPLETAG;
- /*
- When using Tagged Queuing with Simple Queue Tags, it
- appears that disk drive controllers do not guarantee that
- a queued command will not remain in a disconnected state
- indefinitely if commands that read or write nearer the
- head position continue to arrive without interruption.
- Therefore, for each Target Device this driver keeps track
- of the last time either the queue was empty or an Ordered
- Queue Tag was issued. If more than 4 seconds (one fifth
- of the 20 second disk timeout) have elapsed since this
- last sequence point, this command will be issued with an
- Ordered Queue Tag rather than a Simple Queue Tag, which
- forces the Target Device to complete all previously
- queued commands before this command may be executed.
- */
- if (adapter->active_cmds[tgt_id] == 0)
- adapter->last_seqpoint[tgt_id] = jiffies;
- else if (time_after(jiffies,
- adapter->last_seqpoint[tgt_id] + 4 * HZ)) {
- adapter->last_seqpoint[tgt_id] = jiffies;
- queuetag = BLOGIC_ORDEREDTAG;
- }
- if (adapter->ext_lun) {
- ccb->tag_enable = true;
- ccb->queuetag = queuetag;
- } else {
- ccb->legacytag_enable = true;
- ccb->legacy_tag = queuetag;
- }
- }
- memcpy(ccb->cdb, cdb, cdblen);
- ccb->sense_datalen = SCSI_SENSE_BUFFERSIZE;
- ccb->command = command;
- sense_buf = pci_map_single(adapter->pci_device,
- command->sense_buffer, ccb->sense_datalen,
- PCI_DMA_FROMDEVICE);
- if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) {
- blogic_err("DMA mapping for sense data buffer failed\n",
- adapter);
- blogic_dealloc_ccb(ccb, 0);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
- ccb->sensedata = sense_buf;
- command->scsi_done = comp_cb;
- if (blogic_multimaster_type(adapter)) {
- /*
- Place the CCB in an Outgoing Mailbox. The higher levels
- of the SCSI Subsystem should not attempt to queue more
- commands than can be placed in Outgoing Mailboxes, so
- there should always be one free. In the unlikely event
- that there are none available, wait 1 second and try
- again. If that fails, the Host Adapter is probably hung
- so signal an error as a Host Adapter Hard Reset should
- be initiated soon.
- */
- if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, ccb)) {
- spin_unlock_irq(adapter->scsi_host->host_lock);
- blogic_warn("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", adapter);
- blogic_delay(1);
- spin_lock_irq(adapter->scsi_host->host_lock);
- if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START,
- ccb)) {
- blogic_warn("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", adapter);
- blogic_dealloc_ccb(ccb, 1);
- command->result = DID_ERROR << 16;
- command->scsi_done(command);
- }
- }
- } else {
- /*
- Call the FlashPoint SCCB Manager to start execution of
- the CCB.
- */
- ccb->status = BLOGIC_CCB_ACTIVE;
- adapter->active_cmds[tgt_id]++;
- tgt_stats[tgt_id].cmds_tried++;
- FlashPoint_StartCCB(adapter->cardhandle, ccb);
- /*
- The Command may have already completed and
- blogic_qcompleted_ccb been called, or it may still be
- pending.
- */
- if (ccb->status == BLOGIC_CCB_COMPLETE)
- blogic_process_ccbs(adapter);
- }
- return 0;
- }
- static DEF_SCSI_QCMD(blogic_qcmd)
- #if 0
- /*
- blogic_abort aborts Command if possible.
- */
- static int blogic_abort(struct scsi_cmnd *command)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) command->device->host->hostdata;
- int tgt_id = command->device->id;
- struct blogic_ccb *ccb;
- blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_request);
- /*
- Attempt to find an Active CCB for this Command. If no Active
- CCB for this Command is found, then no Abort is necessary.
- */
- for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all)
- if (ccb->command == command)
- break;
- if (ccb == NULL) {
- blogic_warn("Unable to Abort Command to Target %d - No CCB Found\n", adapter, tgt_id);
- return SUCCESS;
- } else if (ccb->status == BLOGIC_CCB_COMPLETE) {
- blogic_warn("Unable to Abort Command to Target %d - CCB Completed\n", adapter, tgt_id);
- return SUCCESS;
- } else if (ccb->status == BLOGIC_CCB_RESET) {
- blogic_warn("Unable to Abort Command to Target %d - CCB Reset\n", adapter, tgt_id);
- return SUCCESS;
- }
- if (blogic_multimaster_type(adapter)) {
- /*
- Attempt to Abort this CCB. MultiMaster Firmware versions
- prior to 5.xx do not generate Abort Tag messages, but only
- generate the non-tagged Abort message. Since non-tagged
- commands are not sent by the Host Adapter until the queue
- of outstanding tagged commands has completed, and the
- Abort message is treated as a non-tagged command, it is
- effectively impossible to abort commands when Tagged
- Queuing is active. Firmware version 5.xx does generate
- Abort Tag messages, so it is possible to abort commands
- when Tagged Queuing is active.
- */
- if (adapter->tgt_flags[tgt_id].tagq_active &&
- adapter->fw_ver[0] < '5') {
- blogic_warn("Unable to Abort CCB #%ld to Target %d - Abort Tag Not Supported\n", adapter, ccb->serial, tgt_id);
- return FAILURE;
- } else if (blogic_write_outbox(adapter, BLOGIC_MBOX_ABORT,
- ccb)) {
- blogic_warn("Aborting CCB #%ld to Target %d\n",
- adapter, ccb->serial, tgt_id);
- blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_tried);
- return SUCCESS;
- } else {
- blogic_warn("Unable to Abort CCB #%ld to Target %d - No Outgoing Mailboxes\n", adapter, ccb->serial, tgt_id);
- return FAILURE;
- }
- } else {
- /*
- Call the FlashPoint SCCB Manager to abort execution of
- the CCB.
- */
- blogic_warn("Aborting CCB #%ld to Target %d\n", adapter,
- ccb->serial, tgt_id);
- blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_tried);
- FlashPoint_AbortCCB(adapter->cardhandle, ccb);
- /*
- The Abort may have already been completed and
- blogic_qcompleted_ccb been called, or it
- may still be pending.
- */
- if (ccb->status == BLOGIC_CCB_COMPLETE)
- blogic_process_ccbs(adapter);
- return SUCCESS;
- }
- return SUCCESS;
- }
- #endif
- /*
- blogic_resetadapter resets Host Adapter if possible, marking all
- currently executing SCSI Commands as having been Reset.
- */
- static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset)
- {
- struct blogic_ccb *ccb;
- int tgt_id;
- /*
- * Attempt to Reset and Reinitialize the Host Adapter.
- */
- if (!(blogic_hwreset(adapter, hard_reset) &&
- blogic_initadapter(adapter))) {
- blogic_err("Resetting %s Failed\n", adapter,
- adapter->full_model);
- return FAILURE;
- }
- /*
- * Deallocate all currently executing CCBs.
- */
- for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all)
- if (ccb->status == BLOGIC_CCB_ACTIVE)
- blogic_dealloc_ccb(ccb, 1);
- /*
- * Wait a few seconds between the Host Adapter Hard Reset which
- * initiates a SCSI Bus Reset and issuing any SCSI Commands. Some
- * SCSI devices get confused if they receive SCSI Commands too soon
- * after a SCSI Bus Reset.
- */
- if (hard_reset) {
- spin_unlock_irq(adapter->scsi_host->host_lock);
- blogic_delay(adapter->bus_settle_time);
- spin_lock_irq(adapter->scsi_host->host_lock);
- }
- for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) {
- adapter->last_resettried[tgt_id] = jiffies;
- adapter->last_resetdone[tgt_id] = jiffies;
- }
- return SUCCESS;
- }
- /*
- blogic_diskparam returns the Heads/Sectors/Cylinders BIOS Disk
- Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, and
- the appropriate number of cylinders so as not to exceed drive capacity. In
- order for disks equal to or larger than 1 GB to be addressable by the BIOS
- without exceeding the BIOS limitation of 1024 cylinders, Extended Translation
- may be enabled in AutoSCSI on FlashPoint Host Adapters and on "W" and "C"
- series MultiMaster Host Adapters, or by a dip switch setting on "S" and "A"
- series MultiMaster Host Adapters. With Extended Translation enabled, drives
- between 1 GB inclusive and 2 GB exclusive are given a disk geometry of 128
- heads and 32 sectors, and drives above 2 GB inclusive are given a disk
- geometry of 255 heads and 63 sectors. However, if the BIOS detects that the
- Extended Translation setting does not match the geometry in the partition
- table, then the translation inferred from the partition table will be used by
- the BIOS, and a warning may be displayed.
- */
- static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev,
- sector_t capacity, int *params)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) sdev->host->hostdata;
- struct bios_diskparam *diskparam = (struct bios_diskparam *) params;
- unsigned char *buf;
- if (adapter->ext_trans_enable && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */) {
- if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */) {
- diskparam->heads = 255;
- diskparam->sectors = 63;
- } else {
- diskparam->heads = 128;
- diskparam->sectors = 32;
- }
- } else {
- diskparam->heads = 64;
- diskparam->sectors = 32;
- }
- diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors);
- buf = scsi_bios_ptable(dev);
- if (buf == NULL)
- return 0;
- /*
- If the boot sector partition table flag is valid, search for
- a partition table entry whose end_head matches one of the
- standard BusLogic geometry translations (64/32, 128/32, or 255/63).
- */
- if (*(unsigned short *) (buf + 64) == 0xAA55) {
- struct partition *part1_entry = (struct partition *) buf;
- struct partition *part_entry = part1_entry;
- int saved_cyl = diskparam->cylinders, part_no;
- unsigned char part_end_head = 0, part_end_sector = 0;
- for (part_no = 0; part_no < 4; part_no++) {
- part_end_head = part_entry->end_head;
- part_end_sector = part_entry->end_sector & 0x3F;
- if (part_end_head == 64 - 1) {
- diskparam->heads = 64;
- diskparam->sectors = 32;
- break;
- } else if (part_end_head == 128 - 1) {
- diskparam->heads = 128;
- diskparam->sectors = 32;
- break;
- } else if (part_end_head == 255 - 1) {
- diskparam->heads = 255;
- diskparam->sectors = 63;
- break;
- }
- part_entry++;
- }
- if (part_no == 4) {
- part_end_head = part1_entry->end_head;
- part_end_sector = part1_entry->end_sector & 0x3F;
- }
- diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors);
- if (part_no < 4 && part_end_sector == diskparam->sectors) {
- if (diskparam->cylinders != saved_cyl)
- blogic_warn("Adopting Geometry %d/%d from Partition Table\n", adapter, diskparam->heads, diskparam->sectors);
- } else if (part_end_head > 0 || part_end_sector > 0) {
- blogic_warn("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", adapter, part_end_head + 1, part_end_sector);
- blogic_warn("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", adapter, diskparam->heads, diskparam->sectors);
- }
- }
- kfree(buf);
- return 0;
- }
- /*
- BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>.
- */
- static int blogic_write_info(struct Scsi_Host *shost, char *procbuf,
- int bytes_avail)
- {
- struct blogic_adapter *adapter =
- (struct blogic_adapter *) shost->hostdata;
- struct blogic_tgt_stats *tgt_stats;
- tgt_stats = adapter->tgt_stats;
- adapter->ext_resets = 0;
- adapter->adapter_intern_errors = 0;
- memset(tgt_stats, 0, BLOGIC_MAXDEV * sizeof(struct blogic_tgt_stats));
- return 0;
- }
- static int blogic_show_info(struct seq_file *m, struct Scsi_Host *shost)
- {
- struct blogic_adapter *adapter = (struct blogic_adapter *) shost->hostdata;
- struct blogic_tgt_stats *tgt_stats;
- int tgt;
- tgt_stats = adapter->tgt_stats;
- seq_write(m, adapter->msgbuf, adapter->msgbuflen);
- seq_printf(m, "\n\
- Current Driver Queue Depth: %d\n\
- Currently Allocated CCBs: %d\n", adapter->drvr_qdepth, adapter->alloc_ccbs);
- seq_puts(m, "\n\n\
- DATA TRANSFER STATISTICS\n\
- \n\
- Target Tagged Queuing Queue Depth Active Attempted Completed\n\
- ====== ============== =========== ====== ========= =========\n");
- for (tgt = 0; tgt < adapter->maxdev; tgt++) {
- struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt];
- if (!tgt_flags->tgt_exists)
- continue;
- seq_printf(m, " %2d %s", tgt, (tgt_flags->tagq_ok ? (tgt_flags->tagq_active ? " Active" : (adapter->tagq_ok & (1 << tgt)
- ? " Permitted" : " Disabled"))
- : "Not Supported"));
- seq_printf(m,
- " %3d %3u %9u %9u\n", adapter->qdepth[tgt], adapter->active_cmds[tgt], tgt_stats[tgt].cmds_tried, tgt_stats[tgt].cmds_complete);
- }
- seq_puts(m, "\n\
- Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\
- ====== ============= ============== =================== ===================\n");
- for (tgt = 0; tgt < adapter->maxdev; tgt++) {
- struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt];
- if (!tgt_flags->tgt_exists)
- continue;
- seq_printf(m, " %2d %9u %9u", tgt, tgt_stats[tgt].read_cmds, tgt_stats[tgt].write_cmds);
- if (tgt_stats[tgt].bytesread.billions > 0)
- seq_printf(m, " %9u%09u", tgt_stats[tgt].bytesread.billions, tgt_stats[tgt].bytesread.units);
- else
- seq_printf(m, " %9u", tgt_stats[tgt].bytesread.units);
- if (tgt_stats[tgt].byteswritten.billions > 0)
- seq_printf(m, " %9u%09u\n", tgt_stats[tgt].byteswritten.billions, tgt_stats[tgt].byteswritten.units);
- else
- seq_printf(m, " %9u\n", tgt_stats[tgt].byteswritten.units);
- }
- seq_puts(m, "\n\
- Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\
- ====== ======= ========= ========= ========= ========= =========\n");
- for (tgt = 0; tgt < adapter->maxdev; tgt++) {
- struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt];
- if (!tgt_flags->tgt_exists)
- continue;
- seq_printf(m,
- " %2d Read %9u %9u %9u %9u %9u\n", tgt,
- tgt_stats[tgt].read_sz_buckets[0],
- tgt_stats[tgt].read_sz_buckets[1], tgt_stats[tgt].read_sz_buckets[2], tgt_stats[tgt].read_sz_buckets[3], tgt_stats[tgt].read_sz_buckets[4]);
- seq_printf(m,
- " %2d Write %9u %9u %9u %9u %9u\n", tgt,
- tgt_stats[tgt].write_sz_buckets[0],
- tgt_stats[tgt].write_sz_buckets[1], tgt_stats[tgt].write_sz_buckets[2], tgt_stats[tgt].write_sz_buckets[3], tgt_stats[tgt].write_sz_buckets[4]);
- }
- seq_puts(m, "\n\
- Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\
- ====== ======= ========= ========= ========= ========= =========\n");
- for (tgt = 0; tgt < adapter->maxdev; tgt++) {
- struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt];
- if (!tgt_flags->tgt_exists)
- continue;
- seq_printf(m,
- " %2d Read %9u %9u %9u %9u %9u\n", tgt,
- tgt_stats[tgt].read_sz_buckets[5],
- tgt_stats[tgt].read_sz_buckets[6], tgt_stats[tgt].read_sz_buckets[7], tgt_stats[tgt].read_sz_buckets[8], tgt_stats[tgt].read_sz_buckets[9]);
- seq_printf(m,
- " %2d Write %9u %9u %9u %9u %9u\n", tgt,
- tgt_stats[tgt].write_sz_buckets[5],
- tgt_stats[tgt].write_sz_buckets[6], tgt_stats[tgt].write_sz_buckets[7], tgt_stats[tgt].write_sz_buckets[8], tgt_stats[tgt].write_sz_buckets[9]);
- }
- seq_puts(m, "\n\n\
- ERROR RECOVERY STATISTICS\n\
- \n\
- Command Aborts Bus Device Resets Host Adapter Resets\n\
- Target Requested Completed Requested Completed Requested Completed\n\
- ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\
- ====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n");
- for (tgt = 0; tgt < adapter->maxdev; tgt++) {
- struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt];
- if (!tgt_flags->tgt_exists)
- continue;
- seq_printf(m, "\
- %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", tgt, tgt_stats[tgt].aborts_request, tgt_stats[tgt].aborts_tried, tgt_stats[tgt].aborts_done, tgt_stats[tgt].bdr_request, tgt_stats[tgt].bdr_tried, tgt_stats[tgt].bdr_done, tgt_stats[tgt].adatper_reset_req, tgt_stats[tgt].adapter_reset_attempt, tgt_stats[tgt].adapter_reset_done);
- }
- seq_printf(m, "\nExternal Host Adapter Resets: %d\n", adapter->ext_resets);
- seq_printf(m, "Host Adapter Internal Errors: %d\n", adapter->adapter_intern_errors);
- return 0;
- }
- /*
- blogic_msg prints Driver Messages.
- */
- static void blogic_msg(enum blogic_msglevel msglevel, char *fmt,
- struct blogic_adapter *adapter, ...)
- {
- static char buf[BLOGIC_LINEBUF_SIZE];
- static bool begin = true;
- va_list args;
- int len = 0;
- va_start(args, adapter);
- len = vsprintf(buf, fmt, args);
- va_end(args);
- if (msglevel == BLOGIC_ANNOUNCE_LEVEL) {
- static int msglines = 0;
- strcpy(&adapter->msgbuf[adapter->msgbuflen], buf);
- adapter->msgbuflen += len;
- if (++msglines <= 2)
- printk("%sscsi: %s", blogic_msglevelmap[msglevel], buf);
- } else if (msglevel == BLOGIC_INFO_LEVEL) {
- strcpy(&adapter->msgbuf[adapter->msgbuflen], buf);
- adapter->msgbuflen += len;
- if (begin) {
- if (buf[0] != '\n' || len > 1)
- printk("%sscsi%d: %s", blogic_msglevelmap[msglevel], adapter->host_no, buf);
- } else
- printk("%s", buf);
- } else {
- if (begin) {
- if (adapter != NULL && adapter->adapter_initd)
- printk("%sscsi%d: %s", blogic_msglevelmap[msglevel], adapter->host_no, buf);
- else
- printk("%s%s", blogic_msglevelmap[msglevel], buf);
- } else
- printk("%s", buf);
- }
- begin = (buf[len - 1] == '\n');
- }
- /*
- blogic_parse parses an individual option keyword. It returns true
- and updates the pointer if the keyword is recognized and false otherwise.
- */
- static bool __init blogic_parse(char **str, char *keyword)
- {
- char *pointer = *str;
- while (*keyword != '\0') {
- char strch = *pointer++;
- char keywordch = *keyword++;
- if (strch >= 'A' && strch <= 'Z')
- strch += 'a' - 'Z';
- if (keywordch >= 'A' && keywordch <= 'Z')
- keywordch += 'a' - 'Z';
- if (strch != keywordch)
- return false;
- }
- *str = pointer;
- return true;
- }
- /*
- blogic_parseopts handles processing of BusLogic Driver Options
- specifications.
- BusLogic Driver Options may be specified either via the Linux Kernel Command
- Line or via the Loadable Kernel Module Installation Facility. Driver Options
- for multiple host adapters may be specified either by separating the option
- strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
- command line. Individual option specifications for a single host adapter are
- separated by commas. The Probing and Debugging Options apply to all host
- adapters whereas the remaining options apply individually only to the
- selected host adapter.
- The BusLogic Driver Probing Options are described in
- <file:Documentation/scsi/BusLogic.txt>.
- */
- static int __init blogic_parseopts(char *options)
- {
- while (true) {
- struct blogic_drvr_options *drvr_opts =
- &blogic_drvr_options[blogic_drvr_options_count++];
- int tgt_id;
- memset(drvr_opts, 0, sizeof(struct blogic_drvr_options));
- while (*options != '\0' && *options != ';') {
- /* Probing Options. */
- if (blogic_parse(&options, "IO:")) {
- unsigned long io_addr = simple_strtoul(options,
- &options, 0);
- blogic_probe_options.limited_isa = true;
- switch (io_addr) {
- case 0x330:
- blogic_probe_options.probe330 = true;
- break;
- case 0x334:
- blogic_probe_options.probe334 = true;
- break;
- case 0x230:
- blogic_probe_options.probe230 = true;
- break;
- case 0x234:
- blogic_probe_options.probe234 = true;
- break;
- case 0x130:
- blogic_probe_options.probe130 = true;
- break;
- case 0x134:
- blogic_probe_options.probe134 = true;
- break;
- default:
- blogic_err("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, io_addr);
- return 0;
- }
- } else if (blogic_parse(&options, "NoProbeISA"))
- blogic_probe_options.noprobe_isa = true;
- else if (blogic_parse(&options, "NoProbePCI"))
- blogic_probe_options.noprobe_pci = true;
- else if (blogic_parse(&options, "NoProbe"))
- blogic_probe_options.noprobe = true;
- else if (blogic_parse(&options, "NoSortPCI"))
- blogic_probe_options.nosort_pci = true;
- else if (blogic_parse(&options, "MultiMasterFirst"))
- blogic_probe_options.multimaster_first = true;
- else if (blogic_parse(&options, "FlashPointFirst"))
- blogic_probe_options.flashpoint_first = true;
- /* Tagged Queuing Options. */
- else if (blogic_parse(&options, "QueueDepth:[") ||
- blogic_parse(&options, "QD:[")) {
- for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) {
- unsigned short qdepth = simple_strtoul(options, &options, 0);
- if (qdepth > BLOGIC_MAX_TAG_DEPTH) {
- blogic_err("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, qdepth);
- return 0;
- }
- drvr_opts->qdepth[tgt_id] = qdepth;
- if (*options == ',')
- options++;
- else if (*options == ']')
- break;
- else {
- blogic_err("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, options);
- return 0;
- }
- }
- if (*options != ']') {
- blogic_err("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, options);
- return 0;
- } else
- options++;
- } else if (blogic_parse(&options, "QueueDepth:") || blogic_parse(&options, "QD:")) {
- unsigned short qdepth = simple_strtoul(options, &options, 0);
- if (qdepth == 0 ||
- qdepth > BLOGIC_MAX_TAG_DEPTH) {
- blogic_err("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, qdepth);
- return 0;
- }
- drvr_opts->common_qdepth = qdepth;
- for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++)
- drvr_opts->qdepth[tgt_id] = qdepth;
- } else if (blogic_parse(&options, "TaggedQueuing:") ||
- blogic_parse(&options, "TQ:")) {
- if (blogic_parse(&options, "Default")) {
- drvr_opts->tagq_ok = 0x0000;
- drvr_opts->tagq_ok_mask = 0x0000;
- } else if (blogic_parse(&options, "Enable")) {
- drvr_opts->tagq_ok = 0xFFFF;
- drvr_opts->tagq_ok_mask = 0xFFFF;
- } else if (blogic_parse(&options, "Disable")) {
- drvr_opts->tagq_ok = 0x0000;
- drvr_opts->tagq_ok_mask = 0xFFFF;
- } else {
- unsigned short tgt_bit;
- for (tgt_id = 0, tgt_bit = 1;
- tgt_id < BLOGIC_MAXDEV;
- tgt_id++, tgt_bit <<= 1)
- switch (*options++) {
- case 'Y':
- drvr_opts->tagq_ok |= tgt_bit;
- drvr_opts->tagq_ok_mask |= tgt_bit;
- break;
- case 'N':
- drvr_opts->tagq_ok &= ~tgt_bit;
- drvr_opts->tagq_ok_mask |= tgt_bit;
- break;
- case 'X':
- break;
- default:
- options--;
- tgt_id = BLOGIC_MAXDEV;
- break;
- }
- }
- }
- /* Miscellaneous Options. */
- else if (blogic_parse(&options, "BusSettleTime:") ||
- blogic_parse(&options, "BST:")) {
- unsigned short bus_settle_time =
- simple_strtoul(options, &options, 0);
- if (bus_settle_time > 5 * 60) {
- blogic_err("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, bus_settle_time);
- return 0;
- }
- drvr_opts->bus_settle_time = bus_settle_time;
- } else if (blogic_parse(&options,
- "InhibitTargetInquiry"))
- drvr_opts->stop_tgt_inquiry = true;
- /* Debugging Options. */
- else if (blogic_parse(&options, "TraceProbe"))
- blogic_global_options.trace_probe = true;
- else if (blogic_parse(&options, "TraceHardwareReset"))
- blogic_global_options.trace_hw_reset = true;
- else if (blogic_parse(&options, "TraceConfiguration"))
- blogic_global_options.trace_config = true;
- else if (blogic_parse(&options, "TraceErrors"))
- blogic_global_options.trace_err = true;
- else if (blogic_parse(&options, "Debug")) {
- blogic_global_options.trace_probe = true;
- blogic_global_options.trace_hw_reset = true;
- blogic_global_options.trace_config = true;
- blogic_global_options.trace_err = true;
- }
- if (*options == ',')
- options++;
- else if (*options != ';' && *options != '\0') {
- blogic_err("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, options);
- *options = '\0';
- }
- }
- if (!(blogic_drvr_options_count == 0 ||
- blogic_probeinfo_count == 0 ||
- blogic_drvr_options_count == blogic_probeinfo_count)) {
- blogic_err("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL);
- return 0;
- }
- /*
- Tagged Queuing is disabled when the Queue Depth is 1 since queuing
- multiple commands is not possible.
- */
- for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++)
- if (drvr_opts->qdepth[tgt_id] == 1) {
- unsigned short tgt_bit = 1 << tgt_id;
- drvr_opts->tagq_ok &= ~tgt_bit;
- drvr_opts->tagq_ok_mask |= tgt_bit;
- }
- if (*options == ';')
- options++;
- if (*options == '\0')
- return 0;
- }
- return 1;
- }
- /*
- Get it all started
- */
- static struct scsi_host_template blogic_template = {
- .module = THIS_MODULE,
- .proc_name = "BusLogic",
- .write_info = blogic_write_info,
- .show_info = blogic_show_info,
- .name = "BusLogic",
- .info = blogic_drvr_info,
- .queuecommand = blogic_qcmd,
- .slave_configure = blogic_slaveconfig,
- .bios_param = blogic_diskparam,
- .eh_host_reset_handler = blogic_hostreset,
- #if 0
- .eh_abort_handler = blogic_abort,
- #endif
- .unchecked_isa_dma = 1,
- .max_sectors = 128,
- .use_clustering = ENABLE_CLUSTERING,
- };
- /*
- blogic_setup handles processing of Kernel Command Line Arguments.
- */
- static int __init blogic_setup(char *str)
- {
- int ints[3];
- (void) get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] != 0) {
- blogic_err("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL);
- return 0;
- }
- if (str == NULL || *str == '\0')
- return 0;
- return blogic_parseopts(str);
- }
- /*
- * Exit function. Deletes all hosts associated with this driver.
- */
- static void __exit blogic_exit(void)
- {
- struct blogic_adapter *ha, *next;
- list_for_each_entry_safe(ha, next, &blogic_host_list, host_list)
- blogic_deladapter(ha);
- }
- __setup("BusLogic=", blogic_setup);
- #ifdef MODULE
- /*static struct pci_device_id blogic_pci_tbl[] = {
- { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
- };*/
- static const struct pci_device_id blogic_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER)},
- {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC)},
- {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT)},
- {0, },
- };
- #endif
- MODULE_DEVICE_TABLE(pci, blogic_pci_tbl);
- module_init(blogic_init);
- module_exit(blogic_exit);
|