1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522 |
- /*
- * linux/drivers/scsi/esas2r/esas2r_flash.c
- * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
- *
- * Copyright (c) 2001-2013 ATTO Technology, Inc.
- * (mailto:linuxdrivers@attotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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 more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
- *
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
- #include "esas2r.h"
- /* local macro defs */
- #define esas2r_nvramcalc_cksum(n) \
- (esas2r_calc_byte_cksum((u8 *)(n), sizeof(struct esas2r_sas_nvram), \
- SASNVR_CKSUM_SEED))
- #define esas2r_nvramcalc_xor_cksum(n) \
- (esas2r_calc_byte_xor_cksum((u8 *)(n), \
- sizeof(struct esas2r_sas_nvram), 0))
- #define ESAS2R_FS_DRVR_VER 2
- static struct esas2r_sas_nvram default_sas_nvram = {
- { 'E', 'S', 'A', 'S' }, /* signature */
- SASNVR_VERSION, /* version */
- 0, /* checksum */
- 31, /* max_lun_for_target */
- SASNVR_PCILAT_MAX, /* pci_latency */
- SASNVR1_BOOT_DRVR, /* options1 */
- SASNVR2_HEARTBEAT | SASNVR2_SINGLE_BUS /* options2 */
- | SASNVR2_SW_MUX_CTRL,
- SASNVR_COAL_DIS, /* int_coalescing */
- SASNVR_CMDTHR_NONE, /* cmd_throttle */
- 3, /* dev_wait_time */
- 1, /* dev_wait_count */
- 0, /* spin_up_delay */
- 0, /* ssp_align_rate */
- { 0x50, 0x01, 0x08, 0x60, /* sas_addr */
- 0x00, 0x00, 0x00, 0x00 },
- { SASNVR_SPEED_AUTO }, /* phy_speed */
- { SASNVR_MUX_DISABLED }, /* SAS multiplexing */
- { 0 }, /* phy_flags */
- SASNVR_SORT_SAS_ADDR, /* sort_type */
- 3, /* dpm_reqcmd_lmt */
- 3, /* dpm_stndby_time */
- 0, /* dpm_active_time */
- { 0 }, /* phy_target_id */
- SASNVR_VSMH_DISABLED, /* virt_ses_mode */
- SASNVR_RWM_DEFAULT, /* read_write_mode */
- 0, /* link down timeout */
- { 0 } /* reserved */
- };
- static u8 cmd_to_fls_func[] = {
- 0xFF,
- VDA_FLASH_READ,
- VDA_FLASH_BEGINW,
- VDA_FLASH_WRITE,
- VDA_FLASH_COMMIT,
- VDA_FLASH_CANCEL
- };
- static u8 esas2r_calc_byte_xor_cksum(u8 *addr, u32 len, u8 seed)
- {
- u32 cksum = seed;
- u8 *p = (u8 *)&cksum;
- while (len) {
- if (((uintptr_t)addr & 3) == 0)
- break;
- cksum = cksum ^ *addr;
- addr++;
- len--;
- }
- while (len >= sizeof(u32)) {
- cksum = cksum ^ *(u32 *)addr;
- addr += 4;
- len -= 4;
- }
- while (len--) {
- cksum = cksum ^ *addr;
- addr++;
- }
- return p[0] ^ p[1] ^ p[2] ^ p[3];
- }
- static u8 esas2r_calc_byte_cksum(void *addr, u32 len, u8 seed)
- {
- u8 *p = (u8 *)addr;
- u8 cksum = seed;
- while (len--)
- cksum = cksum + p[len];
- return cksum;
- }
- /* Interrupt callback to process FM API write requests. */
- static void esas2r_fmapi_callback(struct esas2r_adapter *a,
- struct esas2r_request *rq)
- {
- struct atto_vda_flash_req *vrq = &rq->vrq->flash;
- struct esas2r_flash_context *fc =
- (struct esas2r_flash_context *)rq->interrupt_cx;
- if (rq->req_stat == RS_SUCCESS) {
- /* Last request was successful. See what to do now. */
- switch (vrq->sub_func) {
- case VDA_FLASH_BEGINW:
- if (fc->sgc.cur_offset == NULL)
- goto commit;
- vrq->sub_func = VDA_FLASH_WRITE;
- rq->req_stat = RS_PENDING;
- break;
- case VDA_FLASH_WRITE:
- commit:
- vrq->sub_func = VDA_FLASH_COMMIT;
- rq->req_stat = RS_PENDING;
- rq->interrupt_cb = fc->interrupt_cb;
- break;
- default:
- break;
- }
- }
- if (rq->req_stat != RS_PENDING)
- /*
- * All done. call the real callback to complete the FM API
- * request. We should only get here if a BEGINW or WRITE
- * operation failed.
- */
- (*fc->interrupt_cb)(a, rq);
- }
- /*
- * Build a flash request based on the flash context. The request status
- * is filled in on an error.
- */
- static void build_flash_msg(struct esas2r_adapter *a,
- struct esas2r_request *rq)
- {
- struct esas2r_flash_context *fc =
- (struct esas2r_flash_context *)rq->interrupt_cx;
- struct esas2r_sg_context *sgc = &fc->sgc;
- u8 cksum = 0;
- /* calculate the checksum */
- if (fc->func == VDA_FLASH_BEGINW) {
- if (sgc->cur_offset)
- cksum = esas2r_calc_byte_xor_cksum(sgc->cur_offset,
- sgc->length,
- 0);
- rq->interrupt_cb = esas2r_fmapi_callback;
- } else {
- rq->interrupt_cb = fc->interrupt_cb;
- }
- esas2r_build_flash_req(a,
- rq,
- fc->func,
- cksum,
- fc->flsh_addr,
- sgc->length);
- esas2r_rq_free_sg_lists(rq, a);
- /*
- * remember the length we asked for. we have to keep track of
- * the current amount done so we know how much to compare when
- * doing the verification phase.
- */
- fc->curr_len = fc->sgc.length;
- if (sgc->cur_offset) {
- /* setup the S/G context to build the S/G table */
- esas2r_sgc_init(sgc, a, rq, &rq->vrq->flash.data.sge[0]);
- if (!esas2r_build_sg_list(a, rq, sgc)) {
- rq->req_stat = RS_BUSY;
- return;
- }
- } else {
- fc->sgc.length = 0;
- }
- /* update the flsh_addr to the next one to write to */
- fc->flsh_addr += fc->curr_len;
- }
- /* determine the method to process the flash request */
- static bool load_image(struct esas2r_adapter *a, struct esas2r_request *rq)
- {
- /*
- * assume we have more to do. if we return with the status set to
- * RS_PENDING, FM API tasks will continue.
- */
- rq->req_stat = RS_PENDING;
- if (test_bit(AF_DEGRADED_MODE, &a->flags))
- /* not suppported for now */;
- else
- build_flash_msg(a, rq);
- return rq->req_stat == RS_PENDING;
- }
- /* boot image fixer uppers called before downloading the image. */
- static void fix_bios(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
- {
- struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_BIOS];
- struct esas2r_pc_image *pi;
- struct esas2r_boot_header *bh;
- pi = (struct esas2r_pc_image *)((u8 *)fi + ch->image_offset);
- bh =
- (struct esas2r_boot_header *)((u8 *)pi +
- le16_to_cpu(pi->header_offset));
- bh->device_id = cpu_to_le16(a->pcid->device);
- /* Recalculate the checksum in the PNP header if there */
- if (pi->pnp_offset) {
- u8 *pnp_header_bytes =
- ((u8 *)pi + le16_to_cpu(pi->pnp_offset));
- /* Identifier - dword that starts at byte 10 */
- *((u32 *)&pnp_header_bytes[10]) =
- cpu_to_le32(MAKEDWORD(a->pcid->subsystem_vendor,
- a->pcid->subsystem_device));
- /* Checksum - byte 9 */
- pnp_header_bytes[9] -= esas2r_calc_byte_cksum(pnp_header_bytes,
- 32, 0);
- }
- /* Recalculate the checksum needed by the PC */
- pi->checksum = pi->checksum -
- esas2r_calc_byte_cksum((u8 *)pi, ch->length, 0);
- }
- static void fix_efi(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
- {
- struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_EFI];
- u32 len = ch->length;
- u32 offset = ch->image_offset;
- struct esas2r_efi_image *ei;
- struct esas2r_boot_header *bh;
- while (len) {
- u32 thislen;
- ei = (struct esas2r_efi_image *)((u8 *)fi + offset);
- bh = (struct esas2r_boot_header *)((u8 *)ei +
- le16_to_cpu(
- ei->header_offset));
- bh->device_id = cpu_to_le16(a->pcid->device);
- thislen = (u32)le16_to_cpu(bh->image_length) * 512;
- if (thislen > len)
- break;
- len -= thislen;
- offset += thislen;
- }
- }
- /* Complete a FM API request with the specified status. */
- static bool complete_fmapi_req(struct esas2r_adapter *a,
- struct esas2r_request *rq, u8 fi_stat)
- {
- struct esas2r_flash_context *fc =
- (struct esas2r_flash_context *)rq->interrupt_cx;
- struct esas2r_flash_img *fi = fc->fi;
- fi->status = fi_stat;
- fi->driver_error = rq->req_stat;
- rq->interrupt_cb = NULL;
- rq->req_stat = RS_SUCCESS;
- if (fi_stat != FI_STAT_IMG_VER)
- memset(fc->scratch, 0, FM_BUF_SZ);
- esas2r_enable_heartbeat(a);
- clear_bit(AF_FLASH_LOCK, &a->flags);
- return false;
- }
- /* Process each phase of the flash download process. */
- static void fw_download_proc(struct esas2r_adapter *a,
- struct esas2r_request *rq)
- {
- struct esas2r_flash_context *fc =
- (struct esas2r_flash_context *)rq->interrupt_cx;
- struct esas2r_flash_img *fi = fc->fi;
- struct esas2r_component_header *ch;
- u32 len;
- u8 *p, *q;
- /* If the previous operation failed, just return. */
- if (rq->req_stat != RS_SUCCESS)
- goto error;
- /*
- * If an upload just completed and the compare length is non-zero,
- * then we just read back part of the image we just wrote. verify the
- * section and continue reading until the entire image is verified.
- */
- if (fc->func == VDA_FLASH_READ
- && fc->cmp_len) {
- ch = &fi->cmp_hdr[fc->comp_typ];
- p = fc->scratch;
- q = (u8 *)fi /* start of the whole gob */
- + ch->image_offset /* start of the current image */
- + ch->length /* end of the current image */
- - fc->cmp_len; /* where we are now */
- /*
- * NOTE - curr_len is the exact count of bytes for the read
- * even when the end is read and its not a full buffer
- */
- for (len = fc->curr_len; len; len--)
- if (*p++ != *q++)
- goto error;
- fc->cmp_len -= fc->curr_len; /* # left to compare */
- /* Update fc and determine the length for the next upload */
- if (fc->cmp_len > FM_BUF_SZ)
- fc->sgc.length = FM_BUF_SZ;
- else
- fc->sgc.length = fc->cmp_len;
- fc->sgc.cur_offset = fc->sgc_offset +
- ((u8 *)fc->scratch - (u8 *)fi);
- }
- /*
- * This code uses a 'while' statement since the next component may
- * have a length = zero. This can happen since some components are
- * not required. At the end of this 'while' we set up the length
- * for the next request and therefore sgc.length can be = 0.
- */
- while (fc->sgc.length == 0) {
- ch = &fi->cmp_hdr[fc->comp_typ];
- switch (fc->task) {
- case FMTSK_ERASE_BOOT:
- /* the BIOS image is written next */
- ch = &fi->cmp_hdr[CH_IT_BIOS];
- if (ch->length == 0)
- goto no_bios;
- fc->task = FMTSK_WRTBIOS;
- fc->func = VDA_FLASH_BEGINW;
- fc->comp_typ = CH_IT_BIOS;
- fc->flsh_addr = FLS_OFFSET_BOOT;
- fc->sgc.length = ch->length;
- fc->sgc.cur_offset = fc->sgc_offset +
- ch->image_offset;
- break;
- case FMTSK_WRTBIOS:
- /*
- * The BIOS image has been written - read it and
- * verify it
- */
- fc->task = FMTSK_READBIOS;
- fc->func = VDA_FLASH_READ;
- fc->flsh_addr = FLS_OFFSET_BOOT;
- fc->cmp_len = ch->length;
- fc->sgc.length = FM_BUF_SZ;
- fc->sgc.cur_offset = fc->sgc_offset
- + ((u8 *)fc->scratch -
- (u8 *)fi);
- break;
- case FMTSK_READBIOS:
- no_bios:
- /*
- * Mark the component header status for the image
- * completed
- */
- ch->status = CH_STAT_SUCCESS;
- /* The MAC image is written next */
- ch = &fi->cmp_hdr[CH_IT_MAC];
- if (ch->length == 0)
- goto no_mac;
- fc->task = FMTSK_WRTMAC;
- fc->func = VDA_FLASH_BEGINW;
- fc->comp_typ = CH_IT_MAC;
- fc->flsh_addr = FLS_OFFSET_BOOT
- + fi->cmp_hdr[CH_IT_BIOS].length;
- fc->sgc.length = ch->length;
- fc->sgc.cur_offset = fc->sgc_offset +
- ch->image_offset;
- break;
- case FMTSK_WRTMAC:
- /* The MAC image has been written - read and verify */
- fc->task = FMTSK_READMAC;
- fc->func = VDA_FLASH_READ;
- fc->flsh_addr -= ch->length;
- fc->cmp_len = ch->length;
- fc->sgc.length = FM_BUF_SZ;
- fc->sgc.cur_offset = fc->sgc_offset
- + ((u8 *)fc->scratch -
- (u8 *)fi);
- break;
- case FMTSK_READMAC:
- no_mac:
- /*
- * Mark the component header status for the image
- * completed
- */
- ch->status = CH_STAT_SUCCESS;
- /* The EFI image is written next */
- ch = &fi->cmp_hdr[CH_IT_EFI];
- if (ch->length == 0)
- goto no_efi;
- fc->task = FMTSK_WRTEFI;
- fc->func = VDA_FLASH_BEGINW;
- fc->comp_typ = CH_IT_EFI;
- fc->flsh_addr = FLS_OFFSET_BOOT
- + fi->cmp_hdr[CH_IT_BIOS].length
- + fi->cmp_hdr[CH_IT_MAC].length;
- fc->sgc.length = ch->length;
- fc->sgc.cur_offset = fc->sgc_offset +
- ch->image_offset;
- break;
- case FMTSK_WRTEFI:
- /* The EFI image has been written - read and verify */
- fc->task = FMTSK_READEFI;
- fc->func = VDA_FLASH_READ;
- fc->flsh_addr -= ch->length;
- fc->cmp_len = ch->length;
- fc->sgc.length = FM_BUF_SZ;
- fc->sgc.cur_offset = fc->sgc_offset
- + ((u8 *)fc->scratch -
- (u8 *)fi);
- break;
- case FMTSK_READEFI:
- no_efi:
- /*
- * Mark the component header status for the image
- * completed
- */
- ch->status = CH_STAT_SUCCESS;
- /* The CFG image is written next */
- ch = &fi->cmp_hdr[CH_IT_CFG];
- if (ch->length == 0)
- goto no_cfg;
- fc->task = FMTSK_WRTCFG;
- fc->func = VDA_FLASH_BEGINW;
- fc->comp_typ = CH_IT_CFG;
- fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
- fc->sgc.length = ch->length;
- fc->sgc.cur_offset = fc->sgc_offset +
- ch->image_offset;
- break;
- case FMTSK_WRTCFG:
- /* The CFG image has been written - read and verify */
- fc->task = FMTSK_READCFG;
- fc->func = VDA_FLASH_READ;
- fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
- fc->cmp_len = ch->length;
- fc->sgc.length = FM_BUF_SZ;
- fc->sgc.cur_offset = fc->sgc_offset
- + ((u8 *)fc->scratch -
- (u8 *)fi);
- break;
- case FMTSK_READCFG:
- no_cfg:
- /*
- * Mark the component header status for the image
- * completed
- */
- ch->status = CH_STAT_SUCCESS;
- /*
- * The download is complete. If in degraded mode,
- * attempt a chip reset.
- */
- if (test_bit(AF_DEGRADED_MODE, &a->flags))
- esas2r_local_reset_adapter(a);
- a->flash_ver = fi->cmp_hdr[CH_IT_BIOS].version;
- esas2r_print_flash_rev(a);
- /* Update the type of boot image on the card */
- memcpy(a->image_type, fi->rel_version,
- sizeof(fi->rel_version));
- complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
- return;
- }
- /* If verifying, don't try reading more than what's there */
- if (fc->func == VDA_FLASH_READ
- && fc->sgc.length > fc->cmp_len)
- fc->sgc.length = fc->cmp_len;
- }
- /* Build the request to perform the next action */
- if (!load_image(a, rq)) {
- error:
- if (fc->comp_typ < fi->num_comps) {
- ch = &fi->cmp_hdr[fc->comp_typ];
- ch->status = CH_STAT_FAILED;
- }
- complete_fmapi_req(a, rq, FI_STAT_FAILED);
- }
- }
- /* Determine the flash image adaptyp for this adapter */
- static u8 get_fi_adap_type(struct esas2r_adapter *a)
- {
- u8 type;
- /* use the device ID to get the correct adap_typ for this HBA */
- switch (a->pcid->device) {
- case ATTO_DID_INTEL_IOP348:
- type = FI_AT_SUN_LAKE;
- break;
- case ATTO_DID_MV_88RC9580:
- case ATTO_DID_MV_88RC9580TS:
- case ATTO_DID_MV_88RC9580TSE:
- case ATTO_DID_MV_88RC9580TL:
- type = FI_AT_MV_9580;
- break;
- default:
- type = FI_AT_UNKNWN;
- break;
- }
- return type;
- }
- /* Size of config + copyright + flash_ver images, 0 for failure. */
- static u32 chk_cfg(u8 *cfg, u32 length, u32 *flash_ver)
- {
- u16 *pw = (u16 *)cfg - 1;
- u32 sz = 0;
- u32 len = length;
- if (len == 0)
- len = FM_BUF_SZ;
- if (flash_ver)
- *flash_ver = 0;
- while (true) {
- u16 type;
- u16 size;
- type = le16_to_cpu(*pw--);
- size = le16_to_cpu(*pw--);
- if (type != FBT_CPYR
- && type != FBT_SETUP
- && type != FBT_FLASH_VER)
- break;
- if (type == FBT_FLASH_VER
- && flash_ver)
- *flash_ver = le32_to_cpu(*(u32 *)(pw - 1));
- sz += size + (2 * sizeof(u16));
- pw -= size / sizeof(u16);
- if (sz > len - (2 * sizeof(u16)))
- break;
- }
- /* See if we are comparing the size to the specified length */
- if (length && sz != length)
- return 0;
- return sz;
- }
- /* Verify that the boot image is valid */
- static u8 chk_boot(u8 *boot_img, u32 length)
- {
- struct esas2r_boot_image *bi = (struct esas2r_boot_image *)boot_img;
- u16 hdroffset = le16_to_cpu(bi->header_offset);
- struct esas2r_boot_header *bh;
- if (bi->signature != le16_to_cpu(0xaa55)
- || (long)hdroffset >
- (long)(65536L - sizeof(struct esas2r_boot_header))
- || (hdroffset & 3)
- || (hdroffset < sizeof(struct esas2r_boot_image))
- || ((u32)hdroffset + sizeof(struct esas2r_boot_header) > length))
- return 0xff;
- bh = (struct esas2r_boot_header *)((char *)bi + hdroffset);
- if (bh->signature[0] != 'P'
- || bh->signature[1] != 'C'
- || bh->signature[2] != 'I'
- || bh->signature[3] != 'R'
- || le16_to_cpu(bh->struct_length) <
- (u16)sizeof(struct esas2r_boot_header)
- || bh->class_code[2] != 0x01
- || bh->class_code[1] != 0x04
- || bh->class_code[0] != 0x00
- || (bh->code_type != CODE_TYPE_PC
- && bh->code_type != CODE_TYPE_OPEN
- && bh->code_type != CODE_TYPE_EFI))
- return 0xff;
- return bh->code_type;
- }
- /* The sum of all the WORDS of the image */
- static u16 calc_fi_checksum(struct esas2r_flash_context *fc)
- {
- struct esas2r_flash_img *fi = fc->fi;
- u16 cksum;
- u32 len;
- u16 *pw;
- for (len = (fi->length - fc->fi_hdr_len) / 2,
- pw = (u16 *)((u8 *)fi + fc->fi_hdr_len),
- cksum = 0;
- len;
- len--, pw++)
- cksum = cksum + le16_to_cpu(*pw);
- return cksum;
- }
- /*
- * Verify the flash image structure. The following verifications will
- * be performed:
- * 1) verify the fi_version is correct
- * 2) verify the checksum of the entire image.
- * 3) validate the adap_typ, action and length fields.
- * 4) validate each component header. check the img_type and
- * length fields
- * 5) validate each component image. validate signatures and
- * local checksums
- */
- static bool verify_fi(struct esas2r_adapter *a,
- struct esas2r_flash_context *fc)
- {
- struct esas2r_flash_img *fi = fc->fi;
- u8 type;
- bool imgerr;
- u16 i;
- u32 len;
- struct esas2r_component_header *ch;
- /* Verify the length - length must even since we do a word checksum */
- len = fi->length;
- if ((len & 1)
- || len < fc->fi_hdr_len) {
- fi->status = FI_STAT_LENGTH;
- return false;
- }
- /* Get adapter type and verify type in flash image */
- type = get_fi_adap_type(a);
- if ((type == FI_AT_UNKNWN) || (fi->adap_typ != type)) {
- fi->status = FI_STAT_ADAPTYP;
- return false;
- }
- /*
- * Loop through each component and verify the img_type and length
- * fields. Keep a running count of the sizes sooze we can verify total
- * size to additive size.
- */
- imgerr = false;
- for (i = 0, len = 0, ch = fi->cmp_hdr;
- i < fi->num_comps;
- i++, ch++) {
- bool cmperr = false;
- /*
- * Verify that the component header has the same index as the
- * image type. The headers must be ordered correctly
- */
- if (i != ch->img_type) {
- imgerr = true;
- ch->status = CH_STAT_INVALID;
- continue;
- }
- switch (ch->img_type) {
- case CH_IT_BIOS:
- type = CODE_TYPE_PC;
- break;
- case CH_IT_MAC:
- type = CODE_TYPE_OPEN;
- break;
- case CH_IT_EFI:
- type = CODE_TYPE_EFI;
- break;
- }
- switch (ch->img_type) {
- case CH_IT_FW:
- case CH_IT_NVR:
- break;
- case CH_IT_BIOS:
- case CH_IT_MAC:
- case CH_IT_EFI:
- if (ch->length & 0x1ff)
- cmperr = true;
- /* Test if component image is present */
- if (ch->length == 0)
- break;
- /* Image is present - verify the image */
- if (chk_boot((u8 *)fi + ch->image_offset, ch->length)
- != type)
- cmperr = true;
- break;
- case CH_IT_CFG:
- /* Test if component image is present */
- if (ch->length == 0) {
- cmperr = true;
- break;
- }
- /* Image is present - verify the image */
- if (!chk_cfg((u8 *)fi + ch->image_offset + ch->length,
- ch->length, NULL))
- cmperr = true;
- break;
- default:
- fi->status = FI_STAT_UNKNOWN;
- return false;
- }
- if (cmperr) {
- imgerr = true;
- ch->status = CH_STAT_INVALID;
- } else {
- ch->status = CH_STAT_PENDING;
- len += ch->length;
- }
- }
- if (imgerr) {
- fi->status = FI_STAT_MISSING;
- return false;
- }
- /* Compare fi->length to the sum of ch->length fields */
- if (len != fi->length - fc->fi_hdr_len) {
- fi->status = FI_STAT_LENGTH;
- return false;
- }
- /* Compute the checksum - it should come out zero */
- if (fi->checksum != calc_fi_checksum(fc)) {
- fi->status = FI_STAT_CHKSUM;
- return false;
- }
- return true;
- }
- /* Fill in the FS IOCTL response data from a completed request. */
- static void esas2r_complete_fs_ioctl(struct esas2r_adapter *a,
- struct esas2r_request *rq)
- {
- struct esas2r_ioctl_fs *fs =
- (struct esas2r_ioctl_fs *)rq->interrupt_cx;
- if (rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
- esas2r_enable_heartbeat(a);
- fs->driver_error = rq->req_stat;
- if (fs->driver_error == RS_SUCCESS)
- fs->status = ATTO_STS_SUCCESS;
- else
- fs->status = ATTO_STS_FAILED;
- }
- /* Prepare an FS IOCTL request to be sent to the firmware. */
- bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
- struct esas2r_ioctl_fs *fs,
- struct esas2r_request *rq,
- struct esas2r_sg_context *sgc)
- {
- u8 cmdcnt = (u8)ARRAY_SIZE(cmd_to_fls_func);
- struct esas2r_ioctlfs_command *fsc = &fs->command;
- u8 func = 0;
- u32 datalen;
- fs->status = ATTO_STS_FAILED;
- fs->driver_error = RS_PENDING;
- if (fs->version > ESAS2R_FS_VER) {
- fs->status = ATTO_STS_INV_VERSION;
- return false;
- }
- if (fsc->command >= cmdcnt) {
- fs->status = ATTO_STS_INV_FUNC;
- return false;
- }
- func = cmd_to_fls_func[fsc->command];
- if (func == 0xFF) {
- fs->status = ATTO_STS_INV_FUNC;
- return false;
- }
- if (fsc->command != ESAS2R_FS_CMD_CANCEL) {
- if ((a->pcid->device != ATTO_DID_MV_88RC9580
- || fs->adap_type != ESAS2R_FS_AT_ESASRAID2)
- && (a->pcid->device != ATTO_DID_MV_88RC9580TS
- || fs->adap_type != ESAS2R_FS_AT_TSSASRAID2)
- && (a->pcid->device != ATTO_DID_MV_88RC9580TSE
- || fs->adap_type != ESAS2R_FS_AT_TSSASRAID2E)
- && (a->pcid->device != ATTO_DID_MV_88RC9580TL
- || fs->adap_type != ESAS2R_FS_AT_TLSASHBA)) {
- fs->status = ATTO_STS_INV_ADAPTER;
- return false;
- }
- if (fs->driver_ver > ESAS2R_FS_DRVR_VER) {
- fs->status = ATTO_STS_INV_DRVR_VER;
- return false;
- }
- }
- if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
- fs->status = ATTO_STS_DEGRADED;
- return false;
- }
- rq->interrupt_cb = esas2r_complete_fs_ioctl;
- rq->interrupt_cx = fs;
- datalen = le32_to_cpu(fsc->length);
- esas2r_build_flash_req(a,
- rq,
- func,
- fsc->checksum,
- le32_to_cpu(fsc->flash_addr),
- datalen);
- if (func == VDA_FLASH_WRITE
- || func == VDA_FLASH_READ) {
- if (datalen == 0) {
- fs->status = ATTO_STS_INV_FUNC;
- return false;
- }
- esas2r_sgc_init(sgc, a, rq, rq->vrq->flash.data.sge);
- sgc->length = datalen;
- if (!esas2r_build_sg_list(a, rq, sgc)) {
- fs->status = ATTO_STS_OUT_OF_RSRC;
- return false;
- }
- }
- if (func == VDA_FLASH_COMMIT)
- esas2r_disable_heartbeat(a);
- esas2r_start_request(a, rq);
- return true;
- }
- static bool esas2r_flash_access(struct esas2r_adapter *a, u32 function)
- {
- u32 starttime;
- u32 timeout;
- u32 intstat;
- u32 doorbell;
- /* Disable chip interrupts awhile */
- if (function == DRBL_FLASH_REQ)
- esas2r_disable_chip_interrupts(a);
- /* Issue the request to the firmware */
- esas2r_write_register_dword(a, MU_DOORBELL_IN, function);
- /* Now wait for the firmware to process it */
- starttime = jiffies_to_msecs(jiffies);
- if (test_bit(AF_CHPRST_PENDING, &a->flags) ||
- test_bit(AF_DISC_PENDING, &a->flags))
- timeout = 40000;
- else
- timeout = 5000;
- while (true) {
- intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
- if (intstat & MU_INTSTAT_DRBL) {
- /* Got a doorbell interrupt. Check for the function */
- doorbell =
- esas2r_read_register_dword(a, MU_DOORBELL_OUT);
- esas2r_write_register_dword(a, MU_DOORBELL_OUT,
- doorbell);
- if (doorbell & function)
- break;
- }
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
- /*
- * Iimeout. If we were requesting flash access,
- * indicate we are done so the firmware knows we gave
- * up. If this was a REQ, we also need to re-enable
- * chip interrupts.
- */
- if (function == DRBL_FLASH_REQ) {
- esas2r_hdebug("flash access timeout");
- esas2r_write_register_dword(a, MU_DOORBELL_IN,
- DRBL_FLASH_DONE);
- esas2r_enable_chip_interrupts(a);
- } else {
- esas2r_hdebug("flash release timeout");
- }
- return false;
- }
- }
- /* if we're done, re-enable chip interrupts */
- if (function == DRBL_FLASH_DONE)
- esas2r_enable_chip_interrupts(a);
- return true;
- }
- #define WINDOW_SIZE ((signed int)MW_DATA_WINDOW_SIZE)
- bool esas2r_read_flash_block(struct esas2r_adapter *a,
- void *to,
- u32 from,
- u32 size)
- {
- u8 *end = (u8 *)to;
- /* Try to acquire access to the flash */
- if (!esas2r_flash_access(a, DRBL_FLASH_REQ))
- return false;
- while (size) {
- u32 len;
- u32 offset;
- u32 iatvr;
- if (test_bit(AF2_SERIAL_FLASH, &a->flags2))
- iatvr = MW_DATA_ADDR_SER_FLASH + (from & -WINDOW_SIZE);
- else
- iatvr = MW_DATA_ADDR_PAR_FLASH + (from & -WINDOW_SIZE);
- esas2r_map_data_window(a, iatvr);
- offset = from & (WINDOW_SIZE - 1);
- len = size;
- if (len > WINDOW_SIZE - offset)
- len = WINDOW_SIZE - offset;
- from += len;
- size -= len;
- while (len--) {
- *end++ = esas2r_read_data_byte(a, offset);
- offset++;
- }
- }
- /* Release flash access */
- esas2r_flash_access(a, DRBL_FLASH_DONE);
- return true;
- }
- bool esas2r_read_flash_rev(struct esas2r_adapter *a)
- {
- u8 bytes[256];
- u16 *pw;
- u16 *pwstart;
- u16 type;
- u16 size;
- u32 sz;
- sz = sizeof(bytes);
- pw = (u16 *)(bytes + sz);
- pwstart = (u16 *)bytes + 2;
- if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_CPYR - sz, sz))
- goto invalid_rev;
- while (pw >= pwstart) {
- pw--;
- type = le16_to_cpu(*pw);
- pw--;
- size = le16_to_cpu(*pw);
- pw -= size / 2;
- if (type == FBT_CPYR
- || type == FBT_SETUP
- || pw < pwstart)
- continue;
- if (type == FBT_FLASH_VER)
- a->flash_ver = le32_to_cpu(*(u32 *)pw);
- break;
- }
- invalid_rev:
- return esas2r_print_flash_rev(a);
- }
- bool esas2r_print_flash_rev(struct esas2r_adapter *a)
- {
- u16 year = LOWORD(a->flash_ver);
- u8 day = LOBYTE(HIWORD(a->flash_ver));
- u8 month = HIBYTE(HIWORD(a->flash_ver));
- if (day == 0
- || month == 0
- || day > 31
- || month > 12
- || year < 2006
- || year > 9999) {
- strcpy(a->flash_rev, "not found");
- a->flash_ver = 0;
- return false;
- }
- sprintf(a->flash_rev, "%02d/%02d/%04d", month, day, year);
- esas2r_hdebug("flash version: %s", a->flash_rev);
- return true;
- }
- /*
- * Find the type of boot image type that is currently in the flash.
- * The chip only has a 64 KB PCI-e expansion ROM
- * size so only one image can be flashed at a time.
- */
- bool esas2r_read_image_type(struct esas2r_adapter *a)
- {
- u8 bytes[256];
- struct esas2r_boot_image *bi;
- struct esas2r_boot_header *bh;
- u32 sz;
- u32 len;
- u32 offset;
- /* Start at the base of the boot images and look for a valid image */
- sz = sizeof(bytes);
- len = FLS_LENGTH_BOOT;
- offset = 0;
- while (true) {
- if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_BOOT +
- offset,
- sz))
- goto invalid_rev;
- bi = (struct esas2r_boot_image *)bytes;
- bh = (struct esas2r_boot_header *)((u8 *)bi +
- le16_to_cpu(
- bi->header_offset));
- if (bi->signature != cpu_to_le16(0xAA55))
- goto invalid_rev;
- if (bh->code_type == CODE_TYPE_PC) {
- strcpy(a->image_type, "BIOS");
- return true;
- } else if (bh->code_type == CODE_TYPE_EFI) {
- struct esas2r_efi_image *ei;
- /*
- * So we have an EFI image. There are several types
- * so see which architecture we have.
- */
- ei = (struct esas2r_efi_image *)bytes;
- switch (le16_to_cpu(ei->machine_type)) {
- case EFI_MACHINE_IA32:
- strcpy(a->image_type, "EFI 32-bit");
- return true;
- case EFI_MACHINE_IA64:
- strcpy(a->image_type, "EFI itanium");
- return true;
- case EFI_MACHINE_X64:
- strcpy(a->image_type, "EFI 64-bit");
- return true;
- case EFI_MACHINE_EBC:
- strcpy(a->image_type, "EFI EBC");
- return true;
- default:
- goto invalid_rev;
- }
- } else {
- u32 thislen;
- /* jump to the next image */
- thislen = (u32)le16_to_cpu(bh->image_length) * 512;
- if (thislen == 0
- || thislen + offset > len
- || bh->indicator == INDICATOR_LAST)
- break;
- offset += thislen;
- }
- }
- invalid_rev:
- strcpy(a->image_type, "no boot images");
- return false;
- }
- /*
- * Read and validate current NVRAM parameters by accessing
- * physical NVRAM directly. if currently stored parameters are
- * invalid, use the defaults.
- */
- bool esas2r_nvram_read_direct(struct esas2r_adapter *a)
- {
- bool result;
- if (down_interruptible(&a->nvram_semaphore))
- return false;
- if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR,
- sizeof(struct esas2r_sas_nvram))) {
- esas2r_hdebug("NVRAM read failed, using defaults");
- return false;
- }
- result = esas2r_nvram_validate(a);
- up(&a->nvram_semaphore);
- return result;
- }
- /* Interrupt callback to process NVRAM completions. */
- static void esas2r_nvram_callback(struct esas2r_adapter *a,
- struct esas2r_request *rq)
- {
- struct atto_vda_flash_req *vrq = &rq->vrq->flash;
- if (rq->req_stat == RS_SUCCESS) {
- /* last request was successful. see what to do now. */
- switch (vrq->sub_func) {
- case VDA_FLASH_BEGINW:
- vrq->sub_func = VDA_FLASH_WRITE;
- rq->req_stat = RS_PENDING;
- break;
- case VDA_FLASH_WRITE:
- vrq->sub_func = VDA_FLASH_COMMIT;
- rq->req_stat = RS_PENDING;
- break;
- case VDA_FLASH_READ:
- esas2r_nvram_validate(a);
- break;
- case VDA_FLASH_COMMIT:
- default:
- break;
- }
- }
- if (rq->req_stat != RS_PENDING) {
- /* update the NVRAM state */
- if (rq->req_stat == RS_SUCCESS)
- set_bit(AF_NVR_VALID, &a->flags);
- else
- clear_bit(AF_NVR_VALID, &a->flags);
- esas2r_enable_heartbeat(a);
- up(&a->nvram_semaphore);
- }
- }
- /*
- * Write the contents of nvram to the adapter's physical NVRAM.
- * The cached copy of the NVRAM is also updated.
- */
- bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq,
- struct esas2r_sas_nvram *nvram)
- {
- struct esas2r_sas_nvram *n = nvram;
- u8 sas_address_bytes[8];
- u32 *sas_address_dwords = (u32 *)&sas_address_bytes[0];
- struct atto_vda_flash_req *vrq = &rq->vrq->flash;
- if (test_bit(AF_DEGRADED_MODE, &a->flags))
- return false;
- if (down_interruptible(&a->nvram_semaphore))
- return false;
- if (n == NULL)
- n = a->nvram;
- /* check the validity of the settings */
- if (n->version > SASNVR_VERSION) {
- up(&a->nvram_semaphore);
- return false;
- }
- memcpy(&sas_address_bytes[0], n->sas_addr, 8);
- if (sas_address_bytes[0] != 0x50
- || sas_address_bytes[1] != 0x01
- || sas_address_bytes[2] != 0x08
- || (sas_address_bytes[3] & 0xF0) != 0x60
- || ((sas_address_bytes[3] & 0x0F) | sas_address_dwords[1]) == 0) {
- up(&a->nvram_semaphore);
- return false;
- }
- if (n->spin_up_delay > SASNVR_SPINUP_MAX)
- n->spin_up_delay = SASNVR_SPINUP_MAX;
- n->version = SASNVR_VERSION;
- n->checksum = n->checksum - esas2r_nvramcalc_cksum(n);
- memcpy(a->nvram, n, sizeof(struct esas2r_sas_nvram));
- /* write the NVRAM */
- n = a->nvram;
- esas2r_disable_heartbeat(a);
- esas2r_build_flash_req(a,
- rq,
- VDA_FLASH_BEGINW,
- esas2r_nvramcalc_xor_cksum(n),
- FLS_OFFSET_NVR,
- sizeof(struct esas2r_sas_nvram));
- if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
- vrq->data.sge[0].length =
- cpu_to_le32(SGE_LAST |
- sizeof(struct esas2r_sas_nvram));
- vrq->data.sge[0].address = cpu_to_le64(
- a->uncached_phys + (u64)((u8 *)n - a->uncached));
- } else {
- vrq->data.prde[0].ctl_len =
- cpu_to_le32(sizeof(struct esas2r_sas_nvram));
- vrq->data.prde[0].address = cpu_to_le64(
- a->uncached_phys
- + (u64)((u8 *)n - a->uncached));
- }
- rq->interrupt_cb = esas2r_nvram_callback;
- esas2r_start_request(a, rq);
- return true;
- }
- /* Validate the cached NVRAM. if the NVRAM is invalid, load the defaults. */
- bool esas2r_nvram_validate(struct esas2r_adapter *a)
- {
- struct esas2r_sas_nvram *n = a->nvram;
- bool rslt = false;
- if (n->signature[0] != 'E'
- || n->signature[1] != 'S'
- || n->signature[2] != 'A'
- || n->signature[3] != 'S') {
- esas2r_hdebug("invalid NVRAM signature");
- } else if (esas2r_nvramcalc_cksum(n)) {
- esas2r_hdebug("invalid NVRAM checksum");
- } else if (n->version > SASNVR_VERSION) {
- esas2r_hdebug("invalid NVRAM version");
- } else {
- set_bit(AF_NVR_VALID, &a->flags);
- rslt = true;
- }
- if (rslt == false) {
- esas2r_hdebug("using defaults");
- esas2r_nvram_set_defaults(a);
- }
- return rslt;
- }
- /*
- * Set the cached NVRAM to defaults. note that this function sets the default
- * NVRAM when it has been determined that the physical NVRAM is invalid.
- * In this case, the SAS address is fabricated.
- */
- void esas2r_nvram_set_defaults(struct esas2r_adapter *a)
- {
- struct esas2r_sas_nvram *n = a->nvram;
- u32 time = jiffies_to_msecs(jiffies);
- clear_bit(AF_NVR_VALID, &a->flags);
- *n = default_sas_nvram;
- n->sas_addr[3] |= 0x0F;
- n->sas_addr[4] = HIBYTE(LOWORD(time));
- n->sas_addr[5] = LOBYTE(LOWORD(time));
- n->sas_addr[6] = a->pcid->bus->number;
- n->sas_addr[7] = a->pcid->devfn;
- }
- void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
- struct esas2r_sas_nvram *nvram)
- {
- u8 sas_addr[8];
- /*
- * in case we are copying the defaults into the adapter, copy the SAS
- * address out first.
- */
- memcpy(&sas_addr[0], a->nvram->sas_addr, 8);
- *nvram = default_sas_nvram;
- memcpy(&nvram->sas_addr[0], &sas_addr[0], 8);
- }
- bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
- struct esas2r_request *rq, struct esas2r_sg_context *sgc)
- {
- struct esas2r_flash_context *fc = &a->flash_context;
- u8 j;
- struct esas2r_component_header *ch;
- if (test_and_set_bit(AF_FLASH_LOCK, &a->flags)) {
- /* flag was already set */
- fi->status = FI_STAT_BUSY;
- return false;
- }
- memcpy(&fc->sgc, sgc, sizeof(struct esas2r_sg_context));
- sgc = &fc->sgc;
- fc->fi = fi;
- fc->sgc_offset = sgc->cur_offset;
- rq->req_stat = RS_SUCCESS;
- rq->interrupt_cx = fc;
- switch (fi->fi_version) {
- case FI_VERSION_1:
- fc->scratch = ((struct esas2r_flash_img *)fi)->scratch_buf;
- fc->num_comps = FI_NUM_COMPS_V1;
- fc->fi_hdr_len = sizeof(struct esas2r_flash_img);
- break;
- default:
- return complete_fmapi_req(a, rq, FI_STAT_IMG_VER);
- }
- if (test_bit(AF_DEGRADED_MODE, &a->flags))
- return complete_fmapi_req(a, rq, FI_STAT_DEGRADED);
- switch (fi->action) {
- case FI_ACT_DOWN: /* Download the components */
- /* Verify the format of the flash image */
- if (!verify_fi(a, fc))
- return complete_fmapi_req(a, rq, fi->status);
- /* Adjust the BIOS fields that are dependent on the HBA */
- ch = &fi->cmp_hdr[CH_IT_BIOS];
- if (ch->length)
- fix_bios(a, fi);
- /* Adjust the EFI fields that are dependent on the HBA */
- ch = &fi->cmp_hdr[CH_IT_EFI];
- if (ch->length)
- fix_efi(a, fi);
- /*
- * Since the image was just modified, compute the checksum on
- * the modified image. First update the CRC for the composite
- * expansion ROM image.
- */
- fi->checksum = calc_fi_checksum(fc);
- /* Disable the heartbeat */
- esas2r_disable_heartbeat(a);
- /* Now start up the download sequence */
- fc->task = FMTSK_ERASE_BOOT;
- fc->func = VDA_FLASH_BEGINW;
- fc->comp_typ = CH_IT_CFG;
- fc->flsh_addr = FLS_OFFSET_BOOT;
- fc->sgc.length = FLS_LENGTH_BOOT;
- fc->sgc.cur_offset = NULL;
- /* Setup the callback address */
- fc->interrupt_cb = fw_download_proc;
- break;
- case FI_ACT_UPSZ: /* Get upload sizes */
- fi->adap_typ = get_fi_adap_type(a);
- fi->flags = 0;
- fi->num_comps = fc->num_comps;
- fi->length = fc->fi_hdr_len;
- /* Report the type of boot image in the rel_version string */
- memcpy(fi->rel_version, a->image_type,
- sizeof(fi->rel_version));
- /* Build the component headers */
- for (j = 0, ch = fi->cmp_hdr;
- j < fi->num_comps;
- j++, ch++) {
- ch->img_type = j;
- ch->status = CH_STAT_PENDING;
- ch->length = 0;
- ch->version = 0xffffffff;
- ch->image_offset = 0;
- ch->pad[0] = 0;
- ch->pad[1] = 0;
- }
- if (a->flash_ver != 0) {
- fi->cmp_hdr[CH_IT_BIOS].version =
- fi->cmp_hdr[CH_IT_MAC].version =
- fi->cmp_hdr[CH_IT_EFI].version =
- fi->cmp_hdr[CH_IT_CFG].version
- = a->flash_ver;
- fi->cmp_hdr[CH_IT_BIOS].status =
- fi->cmp_hdr[CH_IT_MAC].status =
- fi->cmp_hdr[CH_IT_EFI].status =
- fi->cmp_hdr[CH_IT_CFG].status =
- CH_STAT_SUCCESS;
- return complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
- }
- /* fall through */
- case FI_ACT_UP: /* Upload the components */
- default:
- return complete_fmapi_req(a, rq, FI_STAT_INVALID);
- }
- /*
- * If we make it here, fc has been setup to do the first task. Call
- * load_image to format the request, start it, and get out. The
- * interrupt code will call the callback when the first message is
- * complete.
- */
- if (!load_image(a, rq))
- return complete_fmapi_req(a, rq, FI_STAT_FAILED);
- esas2r_start_request(a, rq);
- return true;
- }
|