diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-17 00:47:07 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-17 00:47:07 +0000 |
commit | 6623b2526615353b1e4394ba4c58eeacac5c4883 (patch) | |
tree | 7cb3a3670bc9a0a8ae9063508b2906a8f8d9099a /sys/dev | |
parent | ae7a8d837fc223764b4d9a9380aa80edfbc0d151 (diff) |
Reduce openings to avoid both usual 'EIO' problems in interrupt mode
and apparently some mpt specific problems. With this change installs
to my U320 disk work, and work *fast*.
Try to return XS_TIMEOUT for timeouts rather than XS_NOERROR.
Load on-board firmware. Currently v1.01.61 seems to work well, but
the latest 1.03.23 does not.
With these changes Marco and Milos torture chambers now report no
problems and we should be set for 3.5.
Mostly from Milos Urbanek and Marco Peereboom.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/mpt.c | 168 | ||||
-rw-r--r-- | sys/dev/ic/mpt.h | 7 | ||||
-rw-r--r-- | sys/dev/ic/mpt_openbsd.c | 88 | ||||
-rw-r--r-- | sys/dev/ic/mpt_openbsd.h | 12 |
4 files changed, 260 insertions, 15 deletions
diff --git a/sys/dev/ic/mpt.c b/sys/dev/ic/mpt.c index f21241b5052..9a68392cd91 100644 --- a/sys/dev/ic/mpt.c +++ b/sys/dev/ic/mpt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt.c,v 1.1 2004/03/06 03:03:07 krw Exp $ */ +/* $OpenBSD: mpt.c,v 1.2 2004/03/17 00:47:06 krw Exp $ */ /* $NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $ */ /* @@ -518,6 +518,26 @@ mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) init.ReplyFrameSize = MPT_REPLY_SIZE; init.MsgContext = 0x12071941; + /* + * If we are in a recovery mode and we uploaded the FW image, + * then the fw pointer is not NULL. Skip the upload a second time + * Set this flag if fw set for IOC. + */ + mpt->upload_fw = 0; + + if (mpt->fw_download_boot) { + if (mpt->fw) { + init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE; + } + else { + mpt->upload_fw = 1; + } + } + if (mpt->verbose > 1) { + mpt_prt(mpt, "flags %d, upload_fw %d", init.Flags, + mpt->upload_fw); + } + if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { return(error); } @@ -1108,6 +1128,11 @@ mpt_init(mpt_softc_t *mpt, u_int32_t who) mpt->mpt_global_credits = facts.GlobalCredits; mpt->request_frame_size = facts.RequestFrameSize; + /* save the firmware upload required flag */ + mpt->fw_download_boot = facts.Flags + & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT; + mpt->fw_image_size = facts.FWImageSize; + if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { mpt_prt(mpt, "mpt_get_portfacts failed"); continue; @@ -1167,6 +1192,19 @@ mpt_init(mpt_softc_t *mpt, u_int32_t who) break; } + /* XXX MU correct place the call to fw_upload? */ + if (mpt->upload_fw) { + mpt_prt(mpt, "firmware upload required."); + if (mpt_do_upload(mpt)) { + /* XXX MP should we panic? */ + mpt_prt(mpt, "firmware upload failure!\n"); + } + /* continue; */ + } + else { + mpt_prt(mpt, "firmware upload not required."); + } + /* * Enable asynchronous event reporting */ @@ -1215,3 +1253,131 @@ mpt_init(mpt_softc_t *mpt, u_int32_t who) mpt_enable_ints(mpt); return (0); } + +/* + * mpt_do_upload - create and send FWUpload request to MPT adapter port. + * + * Returns 0 for success, error for failure + */ +int +mpt_do_upload(mpt_softc_t *mpt) +{ + u_int8_t request[MPT_RQSL(mpt)]; + FWUploadReply_t reply; + FWUpload_t *prequest; + FWUploadReply_t *preply; + FWUploadTCSGE_t *ptcsge = NULL; + SGE_SIMPLE32 *se; + int maxsgl; + int sgeoffset; + int i, error; + uint32_t flags; + + if (mpt->fw_image_size == 0 || mpt->fw != NULL) { + return 0; + } + + /* compute the maximum number of elements in the SG list */ + maxsgl = (MPT_RQSL(mpt) - sizeof(MSG_FW_UPLOAD) + + sizeof(SGE_MPI_UNION) - sizeof(FWUploadTCSGE_t)) + / sizeof(SGE_SIMPLE32); + + error = mpt_alloc_fw_mem(mpt, mpt->fw_image_size, maxsgl); + if (error) { + mpt_prt(mpt,"mpt_alloc_fw_mem error: %d\n", error); + return error; + } + + if (mpt->fw_dmap->dm_nsegs > maxsgl) { + mpt_prt(mpt,"nsegs > maxsgl\n"); + return 1; /* XXX */ + } + + prequest = (FWUpload_t *)&request; + preply = (FWUploadReply_t *)&reply; + + memset(prequest, 0, MPT_RQSL(mpt)); + memset(preply, 0, sizeof(reply)); + + prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; + prequest->Function = MPI_FUNCTION_FW_UPLOAD; + prequest->MsgContext = 0; /* XXX MU ok? */ + + ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; + ptcsge->Reserved = 0; + ptcsge->ContextSize = 0; + ptcsge->DetailsLength = 12; + ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; + ptcsge->Reserved1 = 0; + ptcsge->ImageOffset = 0; + ptcsge->ImageSize = mpt->fw_image_size; /* XXX MU check endianess */ + + sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + + sizeof(FWUploadTCSGE_t); + + se = (SGE_SIMPLE32 *) &request[sgeoffset]; + + flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; + + if (mpt->verbose > 1) { + mpt_prt(mpt, "assembling SG list (%d entries)", + mpt->fw_dmap->dm_nsegs); + } + + for (i = 0; i < mpt->fw_dmap->dm_nsegs; i++, se++) { + if (i == mpt->fw_dmap->dm_nsegs - 1) { + /* XXX MU okay? */ + flags |= MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST; + } + + se->Address = mpt->fw_dmap->dm_segs[i].ds_addr; + MPI_pSGE_SET_LENGTH(se, mpt->fw_dmap->dm_segs[i].ds_len); + MPI_pSGE_SET_FLAGS(se, flags); + sgeoffset += sizeof(*se); + } + + mpt_prt(mpt, "sending FW Upload request to IOC (size: %d, " + "img size: %d)", sgeoffset, mpt->fw_image_size); + + if ((error = mpt_send_handshake_cmd(mpt, sgeoffset, prequest)) != 0) { + return(error); + } + + error = mpt_recv_handshake_reply(mpt, sizeof(reply), &reply); + + if (error == 0) { + /* + * Handshake transfer was complete and successfull. + * Check the Reply Frame + */ + int status, transfer_sz; + + status = preply->IOCStatus; + if (mpt->verbose > 1) { + mpt_prt(mpt, "fw_upload reply status %d", status); + } + + if (status == MPI_IOCSTATUS_SUCCESS) { + transfer_sz = preply->ActualImageSize; + if (transfer_sz != mpt->fw_image_size) + error = EFAULT; + } + else { + error = EFAULT; + } + } + + if (error == 0) { + mpt->upload_fw = 0; + } + else { + mpt_prt(mpt, "freeing image memory\n"); + mpt_free_fw_mem(mpt); + mpt->fw = NULL; + } + + return error; +} + diff --git a/sys/dev/ic/mpt.h b/sys/dev/ic/mpt.h index 89c629800c5..b79f32cf802 100644 --- a/sys/dev/ic/mpt.h +++ b/sys/dev/ic/mpt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt.h,v 1.1 2004/03/06 03:03:07 krw Exp $ */ +/* $OpenBSD: mpt.h,v 1.2 2004/03/17 00:47:06 krw Exp $ */ /* $NetBSD: mpt.h,v 1.2 2003/07/08 10:06:31 itojun Exp $ */ /* @@ -177,6 +177,11 @@ void mpt_check_doorbell(mpt_softc_t *); int mpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); int mpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); +/* FW Download Boot */ +int mpt_do_upload(mpt_softc_t *); +int mpt_alloc_fw_mem(mpt_softc_t *, uint32_t , int); +void mpt_free_fw_mem(mpt_softc_t *); + /* mpt_debug.c functions */ void mpt_print_reply(void *); void mpt_print_db(u_int32_t); diff --git a/sys/dev/ic/mpt_openbsd.c b/sys/dev/ic/mpt_openbsd.c index 8387d88e489..4bf4fd0e394 100644 --- a/sys/dev/ic/mpt_openbsd.c +++ b/sys/dev/ic/mpt_openbsd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt_openbsd.c,v 1.5 2004/03/15 09:53:33 deraadt Exp $ */ +/* $OpenBSD: mpt_openbsd.c,v 1.6 2004/03/17 00:47:06 krw Exp $ */ /* $NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $ */ /* @@ -388,13 +388,9 @@ void mpt_attach(mpt_softc_t *mpt) { struct scsi_link *lptr = &mpt->sc_link; - int maxq; mpt->bus = 0; /* XXX ?? */ - maxq = (mpt->mpt_global_credits < MPT_MAX_REQUESTS(mpt)) ? - mpt->mpt_global_credits : MPT_MAX_REQUESTS(mpt); - /* Fill in the scsi_adapter. */ mpt->sc_adapter.scsi_cmd = mpt_action; mpt->sc_adapter.scsi_minphys = mpt_minphys; @@ -403,16 +399,17 @@ mpt_attach(mpt_softc_t *mpt) lptr->adapter_softc = mpt; lptr->device = &mpt_dev; lptr->adapter = &mpt->sc_adapter; - lptr->openings = maxq; lptr->flags = 0; lptr->luns = 8; if (mpt->is_fc) { lptr->adapter_buswidth = 256; lptr->adapter_target = 256; + lptr->openings = 4; /* 1024 requests / 256 targets = 4 each */ } else { lptr->adapter_buswidth = 16; lptr->adapter_target = mpt->mpt_ini_id; + lptr->openings = 16; /* 1024 requests / 16 targets = 16 each */ } #ifdef MPT_DEBUG @@ -678,8 +675,10 @@ mpt_timeout(void *arg) mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); for(index = 0; index < MPT_MAX_REQUESTS(mpt); index++) - if (req == &mpt->request_pool[index]) + if (req == &mpt->request_pool[index]) { + req->debug = REQ_TIMEOUT; break; + } mpt_done(mpt, index); @@ -809,7 +808,12 @@ mpt_done(mpt_softc_t *mpt, uint32_t reply) bus_dmamap_unload(mpt->sc_dmat, req->dmap); } - if (mpt_reply == NULL) { + if (req->debug == REQ_TIMEOUT) { + xs->error = XS_TIMEOUT; + xs->status = SCSI_OK; + xs->resid = 0; + goto done; + } else if (mpt_reply == NULL) { /* * Context reply; report that the command was * successful! @@ -826,10 +830,7 @@ mpt_done(mpt_softc_t *mpt, uint32_t reply) xs->error = XS_NOERROR; xs->status = SCSI_OK; xs->resid = 0; - mpt_free_request(mpt, req); - xs->flags |= ITSDONE; - scsi_done(xs); - return; + goto done; } xs->status = mpt_reply->SCSIStatus; @@ -1501,3 +1502,66 @@ mpt_minphys(struct buf *bp) bp->b_bcount = MPT_MAX_XFER; minphys(bp); } + +/* + * Allocate DMA resources for FW image + * + * img_sz : size of image + * maxsgl : maximum number of DMA segments + */ +int +mpt_alloc_fw_mem(mpt_softc_t *mpt, uint32_t img_sz, int maxsgl) +{ + int error; + + error = bus_dmamem_alloc(mpt->sc_dmat, img_sz, PAGE_SIZE, 0, + &mpt->fw_seg, maxsgl, &mpt->fw_rseg, 0); + if (error) { + mpt_prt(mpt, "unable to allocate fw memory, error = %d\n", error); + goto fw_fail0; + } + + error = bus_dmamem_map(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg, img_sz, + (caddr_t *)&mpt->fw, BUS_DMA_COHERENT); + if (error) { + mpt_prt(mpt, "unable to map fw area, error = %d\n", error); + goto fw_fail1; + } + + error = bus_dmamap_create(mpt->sc_dmat, img_sz, maxsgl, img_sz, + 0, 0, &mpt->fw_dmap); + if (error) { + mpt_prt(mpt, "unable to create request DMA map, error = %d\n", + error); + goto fw_fail2; + } + + error = bus_dmamap_load(mpt->sc_dmat, mpt->fw_dmap, mpt->fw, img_sz, + NULL, 0); + if (error) { + mpt_prt(mpt, "unable to load request DMA map, error = %d\n", error); + goto fw_fail3; + } + + return(error); +fw_fail3: + bus_dmamap_unload(mpt->sc_dmat, mpt->fw_dmap); +fw_fail2: + bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap); +fw_fail1: + bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, img_sz); +fw_fail0: + bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg); + + mpt->fw = NULL; + return (error); +} + +void +mpt_free_fw_mem(mpt_softc_t *mpt) +{ + bus_dmamap_unload(mpt->sc_dmat, mpt->fw_dmap); + bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap); + bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, mpt->fw_image_size); + bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg); +} diff --git a/sys/dev/ic/mpt_openbsd.h b/sys/dev/ic/mpt_openbsd.h index c1d28d4a09c..3238c105577 100644 --- a/sys/dev/ic/mpt_openbsd.h +++ b/sys/dev/ic/mpt_openbsd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt_openbsd.h,v 1.3 2004/03/14 23:14:36 krw Exp $ */ +/* $OpenBSD: mpt_openbsd.h,v 1.4 2004/03/17 00:47:06 krw Exp $ */ /* $NetBSD: mpt_netbsd.h,v 1.2 2003/04/16 23:02:14 thorpej Exp $ */ /* @@ -202,6 +202,8 @@ typedef struct mpt_softc { uint16_t request_frame_size; uint8_t mpt_max_devices; uint8_t mpt_max_buses; + uint8_t fw_download_boot; + uint32_t fw_image_size; /* Port facts */ uint16_t mpt_ini_id; @@ -263,6 +265,13 @@ typedef struct mpt_softc { uint32_t timeouts; /* timeout count */ uint32_t success; /* success after timeout */ + uint8_t upload_fw; /* If set, do a fw upload */ + /* Firmware memory */ + bus_dmamap_t fw_dmap; + int fw_rseg; + bus_dma_segment_t fw_seg; + char *fw; + /* Companion part in a 929 or 1030, or NULL. */ struct mpt_softc *mpt2; @@ -285,6 +294,7 @@ int mpt_dma_mem_alloc(mpt_softc_t *); int mpt_intr(void *); void mpt_prt(mpt_softc_t *, const char *, ...); + #define mpt_set_config_regs(mpt) \ do { \ if ((mpt)->sc_set_config_regs != NULL) \ |