| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * SATA specific part of ATA helper library
- *
- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2004 Jeff Garzik
- * Copyright 2006 Tejun Heo <htejun@gmail.com>
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_eh.h>
- #include <linux/libata.h>
- #include <linux/unaligned.h>
- #include "libata.h"
- #include "libata-transport.h"
- /* debounce timing parameters in msecs { interval, duration, timeout } */
- const unsigned int sata_deb_timing_normal[] = { 5, 100, 2000 };
- EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
- const unsigned int sata_deb_timing_hotplug[] = { 25, 500, 2000 };
- EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
- const unsigned int sata_deb_timing_long[] = { 100, 2000, 5000 };
- EXPORT_SYMBOL_GPL(sata_deb_timing_long);
- /**
- * sata_scr_valid - test whether SCRs are accessible
- * @link: ATA link to test SCR accessibility for
- *
- * Test whether SCRs are accessible for @link.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if SCRs are accessible, 0 otherwise.
- */
- int sata_scr_valid(struct ata_link *link)
- {
- struct ata_port *ap = link->ap;
- return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
- }
- EXPORT_SYMBOL_GPL(sata_scr_valid);
- /**
- * sata_scr_read - read SCR register of the specified port
- * @link: ATA link to read SCR for
- * @reg: SCR to read
- * @val: Place to store read value
- *
- * Read SCR register @reg of @link into *@val. This function is
- * guaranteed to succeed if @link is ap->link, the cable type of
- * the port is SATA and the port implements ->scr_read.
- *
- * LOCKING:
- * None if @link is ap->link. Kernel thread context otherwise.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
- int sata_scr_read(struct ata_link *link, int reg, u32 *val)
- {
- if (ata_is_host_link(link)) {
- if (sata_scr_valid(link))
- return link->ap->ops->scr_read(link, reg, val);
- return -EOPNOTSUPP;
- }
- return sata_pmp_scr_read(link, reg, val);
- }
- EXPORT_SYMBOL_GPL(sata_scr_read);
- /**
- * sata_scr_write - write SCR register of the specified port
- * @link: ATA link to write SCR for
- * @reg: SCR to write
- * @val: value to write
- *
- * Write @val to SCR register @reg of @link. This function is
- * guaranteed to succeed if @link is ap->link, the cable type of
- * the port is SATA and the port implements ->scr_read.
- *
- * LOCKING:
- * None if @link is ap->link. Kernel thread context otherwise.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
- int sata_scr_write(struct ata_link *link, int reg, u32 val)
- {
- if (ata_is_host_link(link)) {
- if (sata_scr_valid(link))
- return link->ap->ops->scr_write(link, reg, val);
- return -EOPNOTSUPP;
- }
- return sata_pmp_scr_write(link, reg, val);
- }
- EXPORT_SYMBOL_GPL(sata_scr_write);
- /**
- * sata_scr_write_flush - write SCR register of the specified port and flush
- * @link: ATA link to write SCR for
- * @reg: SCR to write
- * @val: value to write
- *
- * This function is identical to sata_scr_write() except that this
- * function performs flush after writing to the register.
- *
- * LOCKING:
- * None if @link is ap->link. Kernel thread context otherwise.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
- int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
- {
- if (ata_is_host_link(link)) {
- int rc;
- if (sata_scr_valid(link)) {
- rc = link->ap->ops->scr_write(link, reg, val);
- if (rc == 0)
- rc = link->ap->ops->scr_read(link, reg, &val);
- return rc;
- }
- return -EOPNOTSUPP;
- }
- return sata_pmp_scr_write(link, reg, val);
- }
- EXPORT_SYMBOL_GPL(sata_scr_write_flush);
- /**
- * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
- * @tf: Taskfile to convert
- * @pmp: Port multiplier port
- * @is_cmd: This FIS is for command
- * @fis: Buffer into which data will output
- *
- * Converts a standard ATA taskfile to a Serial ATA
- * FIS structure (Register - Host to Device).
- *
- * LOCKING:
- * Inherited from caller.
- */
- void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
- {
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = pmp & 0xf; /* Port multiplier number*/
- if (is_cmd)
- fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
- fis[2] = tf->command;
- fis[3] = tf->feature;
- fis[4] = tf->lbal;
- fis[5] = tf->lbam;
- fis[6] = tf->lbah;
- fis[7] = tf->device;
- fis[8] = tf->hob_lbal;
- fis[9] = tf->hob_lbam;
- fis[10] = tf->hob_lbah;
- fis[11] = tf->hob_feature;
- fis[12] = tf->nsect;
- fis[13] = tf->hob_nsect;
- fis[14] = 0;
- fis[15] = tf->ctl;
- fis[16] = tf->auxiliary & 0xff;
- fis[17] = (tf->auxiliary >> 8) & 0xff;
- fis[18] = (tf->auxiliary >> 16) & 0xff;
- fis[19] = (tf->auxiliary >> 24) & 0xff;
- }
- EXPORT_SYMBOL_GPL(ata_tf_to_fis);
- /**
- * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
- * @fis: Buffer from which data will be input
- * @tf: Taskfile to output
- *
- * Converts a serial ATA FIS structure to a standard ATA taskfile.
- *
- * LOCKING:
- * Inherited from caller.
- */
- void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
- {
- tf->status = fis[2];
- tf->error = fis[3];
- tf->lbal = fis[4];
- tf->lbam = fis[5];
- tf->lbah = fis[6];
- tf->device = fis[7];
- tf->hob_lbal = fis[8];
- tf->hob_lbam = fis[9];
- tf->hob_lbah = fis[10];
- tf->nsect = fis[12];
- tf->hob_nsect = fis[13];
- }
- EXPORT_SYMBOL_GPL(ata_tf_from_fis);
- /**
- * sata_link_debounce - debounce SATA phy status
- * @link: ATA link to debounce SATA phy status for
- * @params: timing parameters { interval, duration, timeout } in msec
- * @deadline: deadline jiffies for the operation
- *
- * Make sure SStatus of @link reaches stable state, determined by
- * holding the same value where DET is not 1 for @duration polled
- * every @interval, before @timeout. Timeout constraints the
- * beginning of the stable state. Because DET gets stuck at 1 on
- * some controllers after hot unplugging, this functions waits
- * until timeout then returns 0 if DET is stable at 1.
- *
- * @timeout is further limited by @deadline. The sooner of the
- * two is used.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
- int sata_link_debounce(struct ata_link *link, const unsigned int *params,
- unsigned long deadline)
- {
- unsigned int interval = params[0];
- unsigned int duration = params[1];
- unsigned long last_jiffies, t;
- u32 last, cur;
- int rc;
- t = ata_deadline(jiffies, params[2]);
- if (time_before(t, deadline))
- deadline = t;
- if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
- return rc;
- cur &= 0xf;
- last = cur;
- last_jiffies = jiffies;
- while (1) {
- ata_msleep(link->ap, interval);
- if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
- return rc;
- cur &= 0xf;
- /* DET stable? */
- if (cur == last) {
- if (cur == 1 && time_before(jiffies, deadline))
- continue;
- if (time_after(jiffies,
- ata_deadline(last_jiffies, duration)))
- return 0;
- continue;
- }
- /* unstable, start over */
- last = cur;
- last_jiffies = jiffies;
- /* Check deadline. If debouncing failed, return
- * -EPIPE to tell upper layer to lower link speed.
- */
- if (time_after(jiffies, deadline))
- return -EPIPE;
- }
- }
- EXPORT_SYMBOL_GPL(sata_link_debounce);
- /**
- * sata_link_resume - resume SATA link
- * @link: ATA link to resume SATA
- * @params: timing parameters { interval, duration, timeout } in msec
- * @deadline: deadline jiffies for the operation
- *
- * Resume SATA phy @link and debounce it.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
- int sata_link_resume(struct ata_link *link, const unsigned int *params,
- unsigned long deadline)
- {
- int tries = ATA_LINK_RESUME_TRIES;
- u32 scontrol, serror;
- int rc;
- if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- return rc;
- /*
- * Writes to SControl sometimes get ignored under certain
- * controllers (ata_piix SIDPR). Make sure DET actually is
- * cleared.
- */
- do {
- scontrol = (scontrol & 0x0f0) | 0x300;
- if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
- return rc;
- /*
- * Some PHYs react badly if SStatus is pounded
- * immediately after resuming. Delay 200ms before
- * debouncing.
- */
- if (!(link->flags & ATA_LFLAG_NO_DEBOUNCE_DELAY))
- ata_msleep(link->ap, 200);
- /* is SControl restored correctly? */
- if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- return rc;
- } while ((scontrol & 0xf0f) != 0x300 && --tries);
- if ((scontrol & 0xf0f) != 0x300) {
- ata_link_warn(link, "failed to resume link (SControl %X)\n",
- scontrol);
- return 0;
- }
- if (tries < ATA_LINK_RESUME_TRIES)
- ata_link_warn(link, "link resume succeeded after %d retries\n",
- ATA_LINK_RESUME_TRIES - tries);
- if ((rc = sata_link_debounce(link, params, deadline)))
- return rc;
- /* clear SError, some PHYs require this even for SRST to work */
- if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
- rc = sata_scr_write(link, SCR_ERROR, serror);
- return rc != -EINVAL ? rc : 0;
- }
- EXPORT_SYMBOL_GPL(sata_link_resume);
- /**
- * sata_link_scr_lpm - manipulate SControl IPM and SPM fields
- * @link: ATA link to manipulate SControl for
- * @policy: LPM policy to configure
- * @spm_wakeup: initiate LPM transition to active state
- *
- * Manipulate the IPM field of the SControl register of @link
- * according to @policy. If @policy is ATA_LPM_MAX_POWER and
- * @spm_wakeup is %true, the SPM field is manipulated to wake up
- * the link. This function also clears PHYRDY_CHG before
- * returning.
- *
- * LOCKING:
- * EH context.
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
- int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
- bool spm_wakeup)
- {
- struct ata_eh_context *ehc = &link->eh_context;
- bool woken_up = false;
- u32 scontrol;
- int rc;
- rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (rc)
- return rc;
- switch (policy) {
- case ATA_LPM_MAX_POWER:
- /* disable all LPM transitions */
- scontrol |= (0x7 << 8);
- /* initiate transition to active state */
- if (spm_wakeup) {
- scontrol |= (0x4 << 12);
- woken_up = true;
- }
- break;
- case ATA_LPM_MED_POWER:
- /* allow LPM to PARTIAL */
- scontrol &= ~(0x1 << 8);
- scontrol |= (0x6 << 8);
- break;
- case ATA_LPM_MED_POWER_WITH_DIPM:
- case ATA_LPM_MIN_POWER_WITH_PARTIAL:
- case ATA_LPM_MIN_POWER:
- if (ata_link_nr_enabled(link) > 0) {
- /* assume no restrictions on LPM transitions */
- scontrol &= ~(0x7 << 8);
- /*
- * If the controller does not support partial, slumber,
- * or devsleep, then disallow these transitions.
- */
- if (link->ap->host->flags & ATA_HOST_NO_PART)
- scontrol |= (0x1 << 8);
- if (link->ap->host->flags & ATA_HOST_NO_SSC)
- scontrol |= (0x2 << 8);
- if (link->ap->host->flags & ATA_HOST_NO_DEVSLP)
- scontrol |= (0x4 << 8);
- } else {
- /* empty port, power off */
- scontrol &= ~0xf;
- scontrol |= (0x1 << 2);
- }
- break;
- default:
- WARN_ON(1);
- }
- rc = sata_scr_write(link, SCR_CONTROL, scontrol);
- if (rc)
- return rc;
- /* give the link time to transit out of LPM state */
- if (woken_up)
- msleep(10);
- /* clear PHYRDY_CHG from SError */
- ehc->i.serror &= ~SERR_PHYRDY_CHG;
- return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
- }
- EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
- static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
- {
- struct ata_link *host_link = &link->ap->link;
- u32 limit, target, spd;
- limit = link->sata_spd_limit;
- /* Don't configure downstream link faster than upstream link.
- * It doesn't speed up anything and some PMPs choke on such
- * configuration.
- */
- if (!ata_is_host_link(link) && host_link->sata_spd)
- limit &= (1 << host_link->sata_spd) - 1;
- if (limit == UINT_MAX)
- target = 0;
- else
- target = fls(limit);
- spd = (*scontrol >> 4) & 0xf;
- *scontrol = (*scontrol & ~0xf0) | ((target & 0xf) << 4);
- return spd != target;
- }
- /**
- * sata_set_spd_needed - is SATA spd configuration needed
- * @link: Link in question
- *
- * Test whether the spd limit in SControl matches
- * @link->sata_spd_limit. This function is used to determine
- * whether hardreset is necessary to apply SATA spd
- * configuration.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 1 if SATA spd configuration is needed, 0 otherwise.
- */
- static int sata_set_spd_needed(struct ata_link *link)
- {
- u32 scontrol;
- if (sata_scr_read(link, SCR_CONTROL, &scontrol))
- return 1;
- return __sata_set_spd_needed(link, &scontrol);
- }
- /**
- * sata_set_spd - set SATA spd according to spd limit
- * @link: Link to set SATA spd for
- *
- * Set SATA spd of @link according to sata_spd_limit.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 0 if spd doesn't need to be changed, 1 if spd has been
- * changed. Negative errno if SCR registers are inaccessible.
- */
- int sata_set_spd(struct ata_link *link)
- {
- u32 scontrol;
- int rc;
- if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- return rc;
- if (!__sata_set_spd_needed(link, &scontrol))
- return 0;
- if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
- return rc;
- return 1;
- }
- EXPORT_SYMBOL_GPL(sata_set_spd);
- /**
- * sata_down_spd_limit - adjust SATA spd limit downward
- * @link: Link to adjust SATA spd limit for
- * @spd_limit: Additional limit
- *
- * Adjust SATA spd limit of @link downward. Note that this
- * function only adjusts the limit. The change must be applied
- * using sata_set_spd().
- *
- * If @spd_limit is non-zero, the speed is limited to equal to or
- * lower than @spd_limit if such speed is supported. If
- * @spd_limit is slower than any supported speed, only the lowest
- * supported speed is allowed.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 0 on success, negative errno on failure
- */
- int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
- {
- u32 sstatus, spd, mask;
- int rc, bit;
- if (!sata_scr_valid(link))
- return -EOPNOTSUPP;
- /* If SCR can be read, use it to determine the current SPD.
- * If not, use cached value in link->sata_spd.
- */
- rc = sata_scr_read(link, SCR_STATUS, &sstatus);
- if (rc == 0 && ata_sstatus_online(sstatus))
- spd = (sstatus >> 4) & 0xf;
- else
- spd = link->sata_spd;
- mask = link->sata_spd_limit;
- if (mask <= 1)
- return -EINVAL;
- /* unconditionally mask off the highest bit */
- bit = fls(mask) - 1;
- mask &= ~(1 << bit);
- /*
- * Mask off all speeds higher than or equal to the current one. At
- * this point, if current SPD is not available and we previously
- * recorded the link speed from SStatus, the driver has already
- * masked off the highest bit so mask should already be 1 or 0.
- * Otherwise, we should not force 1.5Gbps on a link where we have
- * not previously recorded speed from SStatus. Just return in this
- * case.
- */
- if (spd > 1)
- mask &= (1 << (spd - 1)) - 1;
- else if (link->sata_spd)
- return -EINVAL;
- /* were we already at the bottom? */
- if (!mask)
- return -EINVAL;
- if (spd_limit) {
- if (mask & ((1 << spd_limit) - 1))
- mask &= (1 << spd_limit) - 1;
- else {
- bit = ffs(mask) - 1;
- mask = 1 << bit;
- }
- }
- link->sata_spd_limit = mask;
- ata_link_warn(link, "limiting SATA link speed to %s\n",
- sata_spd_string(fls(mask)));
- return 0;
- }
- /**
- * sata_link_hardreset - reset link via SATA phy reset
- * @link: link to reset
- * @timing: timing parameters { interval, duration, timeout } in msec
- * @deadline: deadline jiffies for the operation
- * @online: optional out parameter indicating link onlineness
- * @check_ready: optional callback to check link readiness
- *
- * SATA phy-reset @link using DET bits of SControl register.
- * After hardreset, link readiness is waited upon using
- * ata_wait_ready() if @check_ready is specified. LLDs are
- * allowed to not specify @check_ready and wait itself after this
- * function returns. Device classification is LLD's
- * responsibility.
- *
- * *@online is set to one iff reset succeeded and @link is online
- * after reset.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
- int sata_link_hardreset(struct ata_link *link, const unsigned int *timing,
- unsigned long deadline,
- bool *online, int (*check_ready)(struct ata_link *))
- {
- u32 scontrol;
- int rc;
- if (online)
- *online = false;
- if (sata_set_spd_needed(link)) {
- /* SATA spec says nothing about how to reconfigure
- * spd. To be on the safe side, turn off phy during
- * reconfiguration. This works for at least ICH7 AHCI
- * and Sil3124.
- */
- if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- goto out;
- scontrol = (scontrol & 0x0f0) | 0x304;
- if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
- goto out;
- sata_set_spd(link);
- }
- /* issue phy wake/reset */
- if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- goto out;
- scontrol = (scontrol & 0x0f0) | 0x301;
- if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
- goto out;
- /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
- * 10.4.2 says at least 1 ms.
- */
- ata_msleep(link->ap, 1);
- /* bring link back */
- rc = sata_link_resume(link, timing, deadline);
- if (rc)
- goto out;
- /* if link is offline nothing more to do */
- if (ata_phys_link_offline(link))
- goto out;
- /* Link is online. From this point, -ENODEV too is an error. */
- if (online)
- *online = true;
- if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) {
- /* If PMP is supported, we have to do follow-up SRST.
- * Some PMPs don't send D2H Reg FIS after hardreset if
- * the first port is empty. Wait only for
- * ATA_TMOUT_PMP_SRST_WAIT.
- */
- if (check_ready) {
- unsigned long pmp_deadline;
- pmp_deadline = ata_deadline(jiffies,
- ATA_TMOUT_PMP_SRST_WAIT);
- if (time_after(pmp_deadline, deadline))
- pmp_deadline = deadline;
- ata_wait_ready(link, pmp_deadline, check_ready);
- }
- rc = -EAGAIN;
- goto out;
- }
- rc = 0;
- if (check_ready)
- rc = ata_wait_ready(link, deadline, check_ready);
- out:
- if (rc && rc != -EAGAIN) {
- /* online is set iff link is online && reset succeeded */
- if (online)
- *online = false;
- }
- return rc;
- }
- EXPORT_SYMBOL_GPL(sata_link_hardreset);
- /**
- * sata_std_hardreset - COMRESET w/o waiting or classification
- * @link: link to reset
- * @class: resulting class of attached device
- * @deadline: deadline jiffies for the operation
- *
- * Standard SATA COMRESET w/o waiting or classification.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 if link offline, -EAGAIN if link online, -errno on errors.
- */
- int sata_std_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
- {
- const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
- bool online;
- int rc;
- rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
- if (online)
- return -EAGAIN;
- return rc;
- }
- EXPORT_SYMBOL_GPL(sata_std_hardreset);
- /**
- * ata_qc_complete_multiple - Complete multiple qcs successfully
- * @ap: port in question
- * @qc_active: new qc_active mask
- *
- * Complete in-flight commands. This functions is meant to be
- * called from low-level driver's interrupt routine to complete
- * requests normally. ap->qc_active and @qc_active is compared
- * and commands are completed accordingly.
- *
- * Always use this function when completing multiple NCQ commands
- * from IRQ handlers instead of calling ata_qc_complete()
- * multiple times to keep IRQ expect status properly in sync.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * Number of completed commands on success, -errno otherwise.
- */
- int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
- {
- u64 done_mask, ap_qc_active = ap->qc_active;
- int nr_done = 0;
- /*
- * If the internal tag is set on ap->qc_active, then we care about
- * bit0 on the passed in qc_active mask. Move that bit up to match
- * the internal tag.
- */
- if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) {
- qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL;
- qc_active ^= qc_active & 0x01;
- }
- done_mask = ap_qc_active ^ qc_active;
- if (unlikely(done_mask & qc_active)) {
- ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",
- ap->qc_active, qc_active);
- return -EINVAL;
- }
- if (ap->ops->qc_ncq_fill_rtf)
- ap->ops->qc_ncq_fill_rtf(ap, done_mask);
- while (done_mask) {
- struct ata_queued_cmd *qc;
- unsigned int tag = __ffs64(done_mask);
- qc = ata_qc_from_tag(ap, tag);
- if (qc) {
- ata_qc_complete(qc);
- nr_done++;
- }
- done_mask &= ~(1ULL << tag);
- }
- return nr_done;
- }
- EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
- /**
- * ata_slave_link_init - initialize slave link
- * @ap: port to initialize slave link for
- *
- * Create and initialize slave link for @ap. This enables slave
- * link handling on the port.
- *
- * In libata, a port contains links and a link contains devices.
- * There is single host link but if a PMP is attached to it,
- * there can be multiple fan-out links. On SATA, there's usually
- * a single device connected to a link but PATA and SATA
- * controllers emulating TF based interface can have two - master
- * and slave.
- *
- * However, there are a few controllers which don't fit into this
- * abstraction too well - SATA controllers which emulate TF
- * interface with both master and slave devices but also have
- * separate SCR register sets for each device. These controllers
- * need separate links for physical link handling
- * (e.g. onlineness, link speed) but should be treated like a
- * traditional M/S controller for everything else (e.g. command
- * issue, softreset).
- *
- * slave_link is libata's way of handling this class of
- * controllers without impacting core layer too much. For
- * anything other than physical link handling, the default host
- * link is used for both master and slave. For physical link
- * handling, separate @ap->slave_link is used. All dirty details
- * are implemented inside libata core layer. From LLD's POV, the
- * only difference is that prereset, hardreset and postreset are
- * called once more for the slave link, so the reset sequence
- * looks like the following.
- *
- * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
- * softreset(M) -> postreset(M) -> postreset(S)
- *
- * Note that softreset is called only for the master. Softreset
- * resets both M/S by definition, so SRST on master should handle
- * both (the standard method will work just fine).
- *
- * LOCKING:
- * Should be called before host is registered.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
- int ata_slave_link_init(struct ata_port *ap)
- {
- struct ata_link *link;
- WARN_ON(ap->slave_link);
- WARN_ON(ap->flags & ATA_FLAG_PMP);
- link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link)
- return -ENOMEM;
- ata_link_init(ap, link, 1);
- ap->slave_link = link;
- return 0;
- }
- EXPORT_SYMBOL_GPL(ata_slave_link_init);
- /**
- * sata_lpm_ignore_phy_events - test if PHY event should be ignored
- * @link: Link receiving the event
- *
- * Test whether the received PHY event has to be ignored or not.
- *
- * LOCKING:
- * None:
- *
- * RETURNS:
- * True if the event has to be ignored.
- */
- bool sata_lpm_ignore_phy_events(struct ata_link *link)
- {
- unsigned long lpm_timeout = link->last_lpm_change +
- msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
- /* if LPM is enabled, PHYRDY doesn't mean anything */
- if (link->lpm_policy > ATA_LPM_MAX_POWER)
- return true;
- /* ignore the first PHY event after the LPM policy changed
- * as it is might be spurious
- */
- if ((link->flags & ATA_LFLAG_CHANGED) &&
- time_before(jiffies, lpm_timeout))
- return true;
- return false;
- }
- EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
- static const char *ata_lpm_policy_names[] = {
- [ATA_LPM_UNKNOWN] = "keep_firmware_settings",
- [ATA_LPM_MAX_POWER] = "max_performance",
- [ATA_LPM_MED_POWER] = "medium_power",
- [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm",
- [ATA_LPM_MIN_POWER_WITH_PARTIAL] = "min_power_with_partial",
- [ATA_LPM_MIN_POWER] = "min_power",
- };
- /*
- * Check if a port supports link power management.
- * Must be called with the port locked.
- */
- static bool ata_scsi_lpm_supported(struct ata_port *ap)
- {
- struct ata_link *link;
- struct ata_device *dev;
- if (ap->flags & ATA_FLAG_NO_LPM)
- return false;
- ata_for_each_link(link, ap, EDGE) {
- ata_for_each_dev(dev, &ap->link, ENABLED) {
- if (dev->quirks & ATA_QUIRK_NOLPM)
- return false;
- }
- }
- return true;
- }
- static ssize_t ata_scsi_lpm_supported_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ata_port *ap = ata_shost_to_port(shost);
- unsigned long flags;
- bool supported;
- spin_lock_irqsave(ap->lock, flags);
- supported = ata_scsi_lpm_supported(ap);
- spin_unlock_irqrestore(ap->lock, flags);
- return sysfs_emit(buf, "%d\n", supported);
- }
- DEVICE_ATTR(link_power_management_supported, S_IRUGO,
- ata_scsi_lpm_supported_show, NULL);
- EXPORT_SYMBOL_GPL(dev_attr_link_power_management_supported);
- static ssize_t ata_scsi_lpm_store(struct device *device,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct Scsi_Host *shost = class_to_shost(device);
- struct ata_port *ap = ata_shost_to_port(shost);
- enum ata_lpm_policy policy;
- unsigned long flags;
- /* UNKNOWN is internal state, iterate from MAX_POWER */
- for (policy = ATA_LPM_MAX_POWER;
- policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
- const char *name = ata_lpm_policy_names[policy];
- if (strncmp(name, buf, strlen(name)) == 0)
- break;
- }
- if (policy == ARRAY_SIZE(ata_lpm_policy_names))
- return -EINVAL;
- spin_lock_irqsave(ap->lock, flags);
- if (!ata_scsi_lpm_supported(ap)) {
- count = -EOPNOTSUPP;
- goto out_unlock;
- }
- ap->target_lpm_policy = policy;
- ata_port_schedule_eh(ap);
- out_unlock:
- spin_unlock_irqrestore(ap->lock, flags);
- return count;
- }
- static ssize_t ata_scsi_lpm_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ata_port *ap = ata_shost_to_port(shost);
- if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
- return -EINVAL;
- return sysfs_emit(buf, "%s\n",
- ata_lpm_policy_names[ap->target_lpm_policy]);
- }
- DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
- ata_scsi_lpm_show, ata_scsi_lpm_store);
- EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
- /**
- * ata_ncq_prio_supported - Check if device supports NCQ Priority
- * @ap: ATA port of the target device
- * @sdev: SCSI device
- * @supported: Address of a boolean to store the result
- *
- * Helper to check if device supports NCQ Priority feature.
- *
- * Context: Any context. Takes and releases @ap->lock.
- *
- * Return:
- * * %0 - OK. Status is stored into @supported
- * * %-ENODEV - Failed to find the ATA device
- */
- int ata_ncq_prio_supported(struct ata_port *ap, struct scsi_device *sdev,
- bool *supported)
- {
- struct ata_device *dev;
- unsigned long flags;
- int rc = 0;
- spin_lock_irqsave(ap->lock, flags);
- dev = ata_scsi_find_dev(ap, sdev);
- if (!dev)
- rc = -ENODEV;
- else
- *supported = dev->flags & ATA_DFLAG_NCQ_PRIO;
- spin_unlock_irqrestore(ap->lock, flags);
- return rc;
- }
- EXPORT_SYMBOL_GPL(ata_ncq_prio_supported);
- static ssize_t ata_ncq_prio_supported_show(struct device *device,
- struct device_attribute *attr,
- char *buf)
- {
- struct scsi_device *sdev = to_scsi_device(device);
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- bool supported;
- int rc;
- rc = ata_ncq_prio_supported(ap, sdev, &supported);
- if (rc)
- return rc;
- return sysfs_emit(buf, "%d\n", supported);
- }
- DEVICE_ATTR(ncq_prio_supported, S_IRUGO, ata_ncq_prio_supported_show, NULL);
- EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_supported);
- /**
- * ata_ncq_prio_enabled - Check if NCQ Priority is enabled
- * @ap: ATA port of the target device
- * @sdev: SCSI device
- * @enabled: Address of a boolean to store the result
- *
- * Helper to check if NCQ Priority feature is enabled.
- *
- * Context: Any context. Takes and releases @ap->lock.
- *
- * Return:
- * * %0 - OK. Status is stored into @enabled
- * * %-ENODEV - Failed to find the ATA device
- */
- int ata_ncq_prio_enabled(struct ata_port *ap, struct scsi_device *sdev,
- bool *enabled)
- {
- struct ata_device *dev;
- unsigned long flags;
- int rc = 0;
- spin_lock_irqsave(ap->lock, flags);
- dev = ata_scsi_find_dev(ap, sdev);
- if (!dev)
- rc = -ENODEV;
- else
- *enabled = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
- spin_unlock_irqrestore(ap->lock, flags);
- return rc;
- }
- EXPORT_SYMBOL_GPL(ata_ncq_prio_enabled);
- static ssize_t ata_ncq_prio_enable_show(struct device *device,
- struct device_attribute *attr,
- char *buf)
- {
- struct scsi_device *sdev = to_scsi_device(device);
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- bool enabled;
- int rc;
- rc = ata_ncq_prio_enabled(ap, sdev, &enabled);
- if (rc)
- return rc;
- return sysfs_emit(buf, "%d\n", enabled);
- }
- /**
- * ata_ncq_prio_enable - Enable/disable NCQ Priority
- * @ap: ATA port of the target device
- * @sdev: SCSI device
- * @enable: true - enable NCQ Priority, false - disable NCQ Priority
- *
- * Helper to enable/disable NCQ Priority feature.
- *
- * Context: Any context. Takes and releases @ap->lock.
- *
- * Return:
- * * %0 - OK. Status is stored into @enabled
- * * %-ENODEV - Failed to find the ATA device
- * * %-EINVAL - NCQ Priority is not supported or CDL is enabled
- */
- int ata_ncq_prio_enable(struct ata_port *ap, struct scsi_device *sdev,
- bool enable)
- {
- struct ata_device *dev;
- unsigned long flags;
- int rc = 0;
- spin_lock_irqsave(ap->lock, flags);
- dev = ata_scsi_find_dev(ap, sdev);
- if (!dev) {
- rc = -ENODEV;
- goto unlock;
- }
- if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) {
- rc = -EINVAL;
- goto unlock;
- }
- if (enable) {
- if (dev->flags & ATA_DFLAG_CDL_ENABLED) {
- ata_dev_err(dev,
- "CDL must be disabled to enable NCQ priority\n");
- rc = -EINVAL;
- goto unlock;
- }
- dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED;
- } else {
- dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
- }
- unlock:
- spin_unlock_irqrestore(ap->lock, flags);
- return rc;
- }
- EXPORT_SYMBOL_GPL(ata_ncq_prio_enable);
- static ssize_t ata_ncq_prio_enable_store(struct device *device,
- struct device_attribute *attr,
- const char *buf, size_t len)
- {
- struct scsi_device *sdev = to_scsi_device(device);
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- bool enable;
- int rc;
- rc = kstrtobool(buf, &enable);
- if (rc)
- return rc;
- rc = ata_ncq_prio_enable(ap, sdev, enable);
- if (rc)
- return rc;
- return len;
- }
- DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
- ata_ncq_prio_enable_show, ata_ncq_prio_enable_store);
- EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_enable);
- static struct attribute *ata_ncq_sdev_attrs[] = {
- &dev_attr_unload_heads.attr,
- &dev_attr_ncq_prio_enable.attr,
- &dev_attr_ncq_prio_supported.attr,
- NULL
- };
- static const struct attribute_group ata_ncq_sdev_attr_group = {
- .attrs = ata_ncq_sdev_attrs
- };
- const struct attribute_group *ata_ncq_sdev_groups[] = {
- &ata_ncq_sdev_attr_group,
- NULL
- };
- EXPORT_SYMBOL_GPL(ata_ncq_sdev_groups);
- static ssize_t
- ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ata_port *ap = ata_shost_to_port(shost);
- if (ap->ops->em_store && (ap->flags & ATA_FLAG_EM))
- return ap->ops->em_store(ap, buf, count);
- return -EINVAL;
- }
- static ssize_t
- ata_scsi_em_message_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ata_port *ap = ata_shost_to_port(shost);
- if (ap->ops->em_show && (ap->flags & ATA_FLAG_EM))
- return ap->ops->em_show(ap, buf);
- return -EINVAL;
- }
- DEVICE_ATTR(em_message, S_IRUGO | S_IWUSR,
- ata_scsi_em_message_show, ata_scsi_em_message_store);
- EXPORT_SYMBOL_GPL(dev_attr_em_message);
- static ssize_t
- ata_scsi_em_message_type_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ata_port *ap = ata_shost_to_port(shost);
- return sysfs_emit(buf, "%d\n", ap->em_message_type);
- }
- DEVICE_ATTR(em_message_type, S_IRUGO,
- ata_scsi_em_message_type_show, NULL);
- EXPORT_SYMBOL_GPL(dev_attr_em_message_type);
- static ssize_t
- ata_scsi_activity_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct scsi_device *sdev = to_scsi_device(dev);
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
- if (atadev && ap->ops->sw_activity_show &&
- (ap->flags & ATA_FLAG_SW_ACTIVITY))
- return ap->ops->sw_activity_show(atadev, buf);
- return -EINVAL;
- }
- static ssize_t
- ata_scsi_activity_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct scsi_device *sdev = to_scsi_device(dev);
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
- enum sw_activity val;
- int rc;
- if (atadev && ap->ops->sw_activity_store &&
- (ap->flags & ATA_FLAG_SW_ACTIVITY)) {
- val = simple_strtoul(buf, NULL, 0);
- switch (val) {
- case OFF: case BLINK_ON: case BLINK_OFF:
- rc = ap->ops->sw_activity_store(atadev, val);
- if (!rc)
- return count;
- else
- return rc;
- }
- }
- return -EINVAL;
- }
- DEVICE_ATTR(sw_activity, S_IWUSR | S_IRUGO, ata_scsi_activity_show,
- ata_scsi_activity_store);
- EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
- /**
- * ata_change_queue_depth - Set a device maximum queue depth
- * @ap: ATA port of the target device
- * @sdev: SCSI device to configure queue depth for
- * @queue_depth: new queue depth
- *
- * Helper to set a device maximum queue depth, usable with both libsas
- * and libata.
- *
- */
- int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
- int queue_depth)
- {
- struct ata_device *dev;
- unsigned long flags;
- int max_queue_depth;
- spin_lock_irqsave(ap->lock, flags);
- dev = ata_scsi_find_dev(ap, sdev);
- if (!dev || queue_depth < 1 || queue_depth == sdev->queue_depth) {
- spin_unlock_irqrestore(ap->lock, flags);
- return sdev->queue_depth;
- }
- /*
- * Make sure that the queue depth requested does not exceed the device
- * capabilities.
- */
- max_queue_depth = min(ATA_MAX_QUEUE, sdev->host->can_queue);
- max_queue_depth = min(max_queue_depth, ata_id_queue_depth(dev->id));
- if (queue_depth > max_queue_depth) {
- spin_unlock_irqrestore(ap->lock, flags);
- return -EINVAL;
- }
- /*
- * If NCQ is not supported by the device or if the target queue depth
- * is 1 (to disable drive side command queueing), turn off NCQ.
- */
- if (queue_depth == 1 || !ata_ncq_supported(dev)) {
- dev->flags |= ATA_DFLAG_NCQ_OFF;
- queue_depth = 1;
- } else {
- dev->flags &= ~ATA_DFLAG_NCQ_OFF;
- }
- spin_unlock_irqrestore(ap->lock, flags);
- if (queue_depth == sdev->queue_depth)
- return sdev->queue_depth;
- return scsi_change_queue_depth(sdev, queue_depth);
- }
- EXPORT_SYMBOL_GPL(ata_change_queue_depth);
- /**
- * ata_scsi_change_queue_depth - SCSI callback for queue depth config
- * @sdev: SCSI device to configure queue depth for
- * @queue_depth: new queue depth
- *
- * This is libata standard hostt->change_queue_depth callback.
- * SCSI will call into this callback when user tries to set queue
- * depth via sysfs.
- *
- * LOCKING:
- * SCSI layer (we don't care)
- *
- * RETURNS:
- * Newly configured queue depth.
- */
- int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
- {
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- return ata_change_queue_depth(ap, sdev, queue_depth);
- }
- EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
- /**
- * ata_sas_device_configure - Default device_configure routine for libata
- * devices
- * @sdev: SCSI device to configure
- * @lim: queue limits
- * @ap: ATA port to which SCSI device is attached
- *
- * RETURNS:
- * Zero.
- */
- int ata_sas_device_configure(struct scsi_device *sdev, struct queue_limits *lim,
- struct ata_port *ap)
- {
- ata_scsi_sdev_config(sdev);
- return ata_scsi_dev_config(sdev, lim, ap->link.device);
- }
- EXPORT_SYMBOL_GPL(ata_sas_device_configure);
- /**
- * ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
- * @cmd: SCSI command to be sent
- * @ap: ATA port to which the command is being sent
- *
- * RETURNS:
- * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
- * 0 otherwise.
- */
- int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
- {
- int rc = 0;
- if (likely(ata_dev_enabled(ap->link.device)))
- rc = __ata_scsi_queuecmd(cmd, ap->link.device);
- else {
- cmd->result = (DID_BAD_TARGET << 16);
- scsi_done(cmd);
- }
- return rc;
- }
- EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
- /**
- * sata_async_notification - SATA async notification handler
- * @ap: ATA port where async notification is received
- *
- * Handler to be called when async notification via SDB FIS is
- * received. This function schedules EH if necessary.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if EH is scheduled, 0 otherwise.
- */
- int sata_async_notification(struct ata_port *ap)
- {
- u32 sntf;
- int rc;
- if (!(ap->flags & ATA_FLAG_AN))
- return 0;
- rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
- if (rc == 0)
- sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
- if (!sata_pmp_attached(ap) || rc) {
- /* PMP is not attached or SNTF is not available */
- if (!sata_pmp_attached(ap)) {
- /* PMP is not attached. Check whether ATAPI
- * AN is configured. If so, notify media
- * change.
- */
- struct ata_device *dev = ap->link.device;
- if ((dev->class == ATA_DEV_ATAPI) &&
- (dev->flags & ATA_DFLAG_AN))
- ata_scsi_media_change_notify(dev);
- return 0;
- } else {
- /* PMP is attached but SNTF is not available.
- * ATAPI async media change notification is
- * not used. The PMP must be reporting PHY
- * status change, schedule EH.
- */
- ata_port_schedule_eh(ap);
- return 1;
- }
- } else {
- /* PMP is attached and SNTF is available */
- struct ata_link *link;
- /* check and notify ATAPI AN */
- ata_for_each_link(link, ap, EDGE) {
- if (!(sntf & (1 << link->pmp)))
- continue;
- if ((link->device->class == ATA_DEV_ATAPI) &&
- (link->device->flags & ATA_DFLAG_AN))
- ata_scsi_media_change_notify(link->device);
- }
- /* If PMP is reporting that PHY status of some
- * downstream ports has changed, schedule EH.
- */
- if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
- ata_port_schedule_eh(ap);
- return 1;
- }
- return 0;
- }
- }
- EXPORT_SYMBOL_GPL(sata_async_notification);
- /**
- * ata_eh_read_log_10h - Read log page 10h for NCQ error details
- * @dev: Device to read log page 10h from
- * @tag: Resulting tag of the failed command
- * @tf: Resulting taskfile registers of the failed command
- *
- * Read log page 10h to obtain NCQ error details and clear error
- * condition.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
- static int ata_eh_read_log_10h(struct ata_device *dev,
- int *tag, struct ata_taskfile *tf)
- {
- u8 *buf = dev->sector_buf;
- unsigned int err_mask;
- u8 csum;
- int i;
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
- if (err_mask)
- return -EIO;
- csum = 0;
- for (i = 0; i < ATA_SECT_SIZE; i++)
- csum += buf[i];
- if (csum)
- ata_dev_warn(dev, "invalid checksum 0x%x on log page 10h\n",
- csum);
- if (buf[0] & 0x80)
- return -ENOENT;
- *tag = buf[0] & 0x1f;
- tf->status = buf[2];
- tf->error = buf[3];
- tf->lbal = buf[4];
- tf->lbam = buf[5];
- tf->lbah = buf[6];
- tf->device = buf[7];
- tf->hob_lbal = buf[8];
- tf->hob_lbam = buf[9];
- tf->hob_lbah = buf[10];
- tf->nsect = buf[12];
- tf->hob_nsect = buf[13];
- if (ata_id_has_ncq_autosense(dev->id) && (tf->status & ATA_SENSE))
- tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
- return 0;
- }
- /**
- * ata_eh_get_ncq_success_sense - Read and process the sense data for
- * successful NCQ commands log page
- * @link: ATA link to get sense data for
- *
- * Read the sense data for successful NCQ commands log page to obtain
- * sense data for all NCQ commands that completed successfully with
- * the sense data available bit set.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
- int ata_eh_get_ncq_success_sense(struct ata_link *link)
- {
- struct ata_device *dev = link->device;
- struct ata_port *ap = dev->link->ap;
- u8 *buf = dev->cdl->ncq_sense_log_buf;
- struct ata_queued_cmd *qc;
- unsigned int err_mask, tag;
- u8 *sense, sk = 0, asc = 0, ascq = 0;
- u64 sense_valid, val;
- u16 extended_sense;
- bool aux_icc_valid;
- int ret = 0;
- err_mask = ata_read_log_page(dev, ATA_LOG_SENSE_NCQ, 0, buf, 2);
- if (err_mask) {
- ata_dev_err(dev,
- "Failed to read Sense Data for Successful NCQ Commands log\n");
- return -EIO;
- }
- /* Check the log header */
- val = get_unaligned_le64(&buf[0]);
- if ((val & 0xffff) != 1 || ((val >> 16) & 0xff) != 0x0f) {
- ata_dev_err(dev,
- "Invalid Sense Data for Successful NCQ Commands log\n");
- return -EIO;
- }
- sense_valid = (u64)buf[8] | ((u64)buf[9] << 8) |
- ((u64)buf[10] << 16) | ((u64)buf[11] << 24);
- extended_sense = get_unaligned_le16(&buf[14]);
- aux_icc_valid = extended_sense & BIT(15);
- ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_EH) ||
- !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
- qc->err_mask ||
- ata_dev_phys_link(qc->dev) != link)
- continue;
- /*
- * If the command does not have any sense data, clear ATA_SENSE.
- * Keep ATA_QCFLAG_EH_SUCCESS_CMD so that command is finished.
- */
- if (!(sense_valid & (1ULL << tag))) {
- qc->result_tf.status &= ~ATA_SENSE;
- continue;
- }
- sense = &buf[32 + 24 * tag];
- sk = sense[0];
- asc = sense[1];
- ascq = sense[2];
- if (!ata_scsi_sense_is_valid(sk, asc, ascq)) {
- ret = -EIO;
- continue;
- }
- qc->result_tf.nsect = sense[6];
- qc->result_tf.hob_nsect = sense[7];
- qc->result_tf.lbal = sense[8];
- qc->result_tf.lbam = sense[9];
- qc->result_tf.lbah = sense[10];
- qc->result_tf.hob_lbal = sense[11];
- qc->result_tf.hob_lbam = sense[12];
- qc->result_tf.hob_lbah = sense[13];
- if (aux_icc_valid)
- qc->result_tf.auxiliary = get_unaligned_le32(&sense[16]);
- /* Set sense without also setting scsicmd->result */
- scsi_build_sense_buffer(dev->flags & ATA_DFLAG_D_SENSE,
- qc->scsicmd->sense_buffer, sk,
- asc, ascq);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
- /*
- * No point in checking the return value, since the command has
- * already completed successfully.
- */
- ata_eh_decide_disposition(qc);
- }
- return ret;
- }
- /**
- * ata_eh_analyze_ncq_error - analyze NCQ error
- * @link: ATA link to analyze NCQ error for
- *
- * Read log page 10h, determine the offending qc and acquire
- * error status TF. For NCQ device errors, all LLDDs have to do
- * is setting AC_ERR_DEV in ehi->err_mask. This function takes
- * care of the rest.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
- void ata_eh_analyze_ncq_error(struct ata_link *link)
- {
- struct ata_port *ap = link->ap;
- struct ata_eh_context *ehc = &link->eh_context;
- struct ata_device *dev = link->device;
- struct ata_queued_cmd *qc;
- struct ata_taskfile tf;
- int tag, rc;
- /* if frozen, we can't do much */
- if (ata_port_is_frozen(ap))
- return;
- /* is it NCQ device error? */
- if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
- return;
- /* has LLDD analyzed already? */
- ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_EH))
- continue;
- if (qc->err_mask)
- return;
- }
- /* okay, this error is ours */
- memset(&tf, 0, sizeof(tf));
- rc = ata_eh_read_log_10h(dev, &tag, &tf);
- if (rc) {
- ata_link_err(link, "failed to read log page 10h (errno=%d)\n",
- rc);
- return;
- }
- if (!(link->sactive & (1 << tag))) {
- ata_link_err(link, "log page 10h reported inactive tag %d\n",
- tag);
- return;
- }
- /* we've got the perpetrator, condemn it */
- qc = __ata_qc_from_tag(ap, tag);
- memcpy(&qc->result_tf, &tf, sizeof(tf));
- qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
- qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
- /*
- * If the device supports NCQ autosense, ata_eh_read_log_10h() will have
- * stored the sense data in qc->result_tf.auxiliary.
- */
- if (qc->result_tf.auxiliary) {
- char sense_key, asc, ascq;
- sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
- asc = (qc->result_tf.auxiliary >> 8) & 0xff;
- ascq = qc->result_tf.auxiliary & 0xff;
- if (ata_scsi_sense_is_valid(sense_key, asc, ascq)) {
- ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc,
- ascq);
- ata_scsi_set_sense_information(dev, qc->scsicmd,
- &qc->result_tf);
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
- }
- }
- ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_EH) ||
- qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
- ata_dev_phys_link(qc->dev) != link)
- continue;
- /* Skip the single QC which caused the NCQ error. */
- if (qc->err_mask)
- continue;
- /*
- * For SATA, the STATUS and ERROR fields are shared for all NCQ
- * commands that were completed with the same SDB FIS.
- * Therefore, we have to clear the ATA_ERR bit for all QCs
- * except the one that caused the NCQ error.
- */
- qc->result_tf.status &= ~ATA_ERR;
- qc->result_tf.error = 0;
- /*
- * If we get a NCQ error, that means that a single command was
- * aborted. All other failed commands for our link should be
- * retried and has no business of going though further scrutiny
- * by ata_eh_link_autopsy().
- */
- qc->flags |= ATA_QCFLAG_RETRY;
- }
- ehc->i.err_mask &= ~AC_ERR_DEV;
- }
- EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
- const struct ata_port_operations sata_port_ops = {
- .inherits = &ata_base_port_ops,
- .qc_defer = ata_std_qc_defer,
- .hardreset = sata_std_hardreset,
- };
- EXPORT_SYMBOL_GPL(sata_port_ops);
|