diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-14 23:14:37 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-14 23:14:37 +0000 |
commit | d4e51de0ee16c9d166ff7880e62f7a753c1aef55 (patch) | |
tree | 8a6f46285c01b8ff4d1fe44507765ce8728adb7c /sys | |
parent | 392e4abf7dc55d5b5204607431c99452fd618bd7 (diff) |
Add first cut at PPR negotiation. From Marco Peereboom.
Call mpt_done() instead of scsi_done() when the command times out.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/mpt_openbsd.c | 437 | ||||
-rw-r--r-- | sys/dev/ic/mpt_openbsd.h | 4 |
2 files changed, 286 insertions, 155 deletions
diff --git a/sys/dev/ic/mpt_openbsd.c b/sys/dev/ic/mpt_openbsd.c index 0af5c1553c3..57892f4677d 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.3 2004/03/10 01:09:29 deraadt Exp $ */ +/* $OpenBSD: mpt_openbsd.c,v 1.4 2004/03/14 23:14:36 krw Exp $ */ /* $NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $ */ /* @@ -101,15 +101,15 @@ #include <dev/ic/mpt.h> /* pulls in all headers */ +#include <machine/stdarg.h> /* for mpt_prt() */ + +static void mpt_run_ppr(mpt_softc_t *); +static int mpt_ppr(mpt_softc_t *, struct scsi_link *, int speed); static int mpt_poll(mpt_softc_t *, struct scsi_xfer *, int); static void mpt_timeout(void *); static void mpt_done(mpt_softc_t *, uint32_t); static int mpt_run_xfer(mpt_softc_t *, struct scsi_xfer *); static void mpt_check_xfer_settings(mpt_softc_t *, struct scsi_xfer *, MSG_SCSI_IO_REQUEST *); -static void mpt_set_xfer_mode(mpt_softc_t *, struct scsi_xfer *); -#if 0 -static void mpt_get_xfer_mode(mpt_softc_t *, struct scsipi_periph *); -#endif static void mpt_ctlop(mpt_softc_t *, void *vmsg, uint32_t); static void mpt_event_notify_reply(mpt_softc_t *, MSG_EVENT_NOTIFY_REPLY *); @@ -129,6 +129,260 @@ static struct scsi_device mpt_dev = NULL, /* Use default 'done' routine */ }; +enum mpt_scsi_speed { U320, U160, U80 }; + +/* + * try speed and + * return 0 if failed + * return 1 if passed + */ +int +mpt_ppr(mpt_softc_t *mpt, struct scsi_link *sc_link, int speed) +{ + fCONFIG_PAGE_SCSI_DEVICE_0 page0; + fCONFIG_PAGE_SCSI_DEVICE_1 page1; + uint8_t tp; + + if (mpt->verbose > 1) { + mpt_prt(mpt, "Entering PPR"); + } + + if (mpt->is_fc) { + /* + * SCSI transport settings don't make any sense for + * Fibre Channel; silently ignore the request. + */ + return 1; /* success */ + } + + /* + * Always allow disconnect; we don't have a way to disable + * it right now, in any case. + */ + mpt->mpt_disc_enable |= (1 << sc_link->target); + + /* + * Enable tagged queueing. + */ + if (sc_link->quirks & SDEV_NOTAGS) + mpt->mpt_tag_enable &= ~(1 << sc_link->target); + else + mpt->mpt_tag_enable |= (1 << sc_link->target); + + page1 = mpt->mpt_dev_page1[sc_link->target]; + + /* + * Set the wide/narrow parameter for the target. + */ + if (sc_link->quirks & SDEV_NOWIDE) + page1.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; + else { + page1.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; + } + + /* + * Set the synchronous parameters for the target. + */ + page1.RequestedParameters &= ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK | + MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK | + MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS | + MPI_SCSIDEVPAGE1_RP_IU); + if (!(sc_link->quirks & SDEV_NOSYNC)) { + int factor, offset, np; + + /* + * Factor: + * 0x08 = U320 = 6.25ns + * 0x09 = U160 = 12.5ns + * 0x0a = U80 = 25ns + */ + factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff; + offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff; + np = 0; + + switch (speed) { + case U320: + /* do nothing */ + break; + + case U160: + factor = 0x09; /* force U160 */ + break; + + case U80: + factor = 0x0a; /* force U80 */ + } + + if (factor < 0x9) { + /* Ultra320 enable QAS & IU */ + np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU; + } + if (factor < 0xa) { + /* >= Ultra160 enable DT transfer */ + np |= MPI_SCSIDEVPAGE1_RP_DT; + } + np |= (factor << 8) | (offset << 16); + page1.RequestedParameters |= np; + } + + /* write parameters out to chip */ + if (mpt_write_cfg_page(mpt, sc_link->target, &page1.Header)) { + mpt_prt(mpt, "unable to write Device Page 1"); + return 0; + } + + /* make sure the parameters were written */ + if (mpt_read_cfg_page(mpt, sc_link->target, &page1.Header)) { + mpt_prt(mpt, "unable to read back Device Page 1"); + return 0; + } + + mpt->mpt_dev_page1[sc_link->target] = page1; + if (mpt->verbose > 1) { + mpt_prt(mpt, + "SPI Target %d Page 1: RequestedParameters %x Config %x", + sc_link->target, + mpt->mpt_dev_page1[sc_link->target].RequestedParameters, + mpt->mpt_dev_page1[sc_link->target].Configuration); + } + + /* use TUR for PPR, use another command if there is a NO_TUR quirk */ + /* FIXME */ + scsi_test_unit_ready(sc_link, TEST_READY_RETRIES_DEFAULT, + scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST | + SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE); + + /* read page 0 back to figure out if the PPR worked */ + page0 = mpt->mpt_dev_page0[sc_link->target]; + if (mpt_read_cfg_page(mpt, sc_link->target, &page0.Header)) { + mpt_prt(mpt, "unable to read Device Page 0"); + return 0; + } + + if (mpt->verbose > 1) { + mpt_prt(mpt, + "SPI Tgt %d Page 0: NParms %x Information %x", + sc_link->target, + page0.NegotiatedParameters, page0.Information); + } + + if (!(page0.NegotiatedParameters & 0x07) && (speed == U320)) { + /* if lowest 3 aren't set the PPR probably failed, retry with other parameters */ + if (mpt->verbose > 1) { + mpt_prt(mpt, "U320 PPR failed"); + } + return 0; + } + + if ((((page0.NegotiatedParameters >> 8) & 0xff) > 0x09) && (speed == U160)) { + /* if transfer period > 0x09 then U160 PPR failed, retry */ + if (mpt->verbose > 1) { + mpt_prt(mpt, "U160 PPR failed"); + } + return 0; + } + + /* + * Bit 3 - PPR rejected: The IOC sets this bit if the device rejects a PPR message. + * Bit 2 - WDTR Rejected: The IOC sets this bit if the device rejects a WDTR message. + * Bit 1 - SDTR Rejected: The IOC sets this bit if the device rejects a SDTR message. + * Bit 0 - 1 A SCSI SDTR, WDTR, or PPR negotiation has occurred with this device. + */ + if (page0.Information & 0x0e) { + /* target rejected PPR message */ + mpt_prt(mpt, "Target %d rejected PPR message with %02x", + sc_link->target, + (uint8_t)page0.Information); + return 0; + } + + /* print PPR results */ + switch ((page0.NegotiatedParameters >> 8) & 0xff) { + case 0x08: + tp = 160; + break; + + case 0x09: + tp = 80; + break; + + case 0x0a: + tp = 40; + break; + + case 0x0b: + tp = 20; + break; + + case 0x0c: + tp = 10; + break; + + default: + tp = 0; + } + + mpt_prt(mpt, + "target %d %s at %dMHz width %dbit offset %d QAS %d DT %d IU %d", + sc_link->target, + tp ? "Synchronous" : "Asynchronous", + tp, + (page0.NegotiatedParameters & 0x20000000) ? 16 : 8, + (page0.NegotiatedParameters >> 16) & 0xff, + (page0.NegotiatedParameters & 0x04) ? 1 : 0, + (page0.NegotiatedParameters & 0x02) ? 1 : 0, + (page0.NegotiatedParameters & 0x01) ? 1 : 0); + + return 1; /* success */ +} + +/* + * Run PPR on all attached devices + */ +void +mpt_run_ppr(mpt_softc_t *mpt) +{ + struct scsi_link *sc_link; + struct device *dev; + u_int8_t target; + u_int16_t buswidth; + + /* walk device list */ + for (dev = TAILQ_FIRST(&alldevs); dev != NULL; dev = TAILQ_NEXT(dev, dv_list)) { + if (dev->dv_parent == (struct device *)mpt) { + /* found scsibus softc */ + buswidth = ((struct scsi_link *)&mpt->sc_link)->adapter_buswidth; + /* printf("mpt_softc: %x scsibus: %x buswidth: %d\n", + mpt, dev, buswidth); */ + /* walk target list */ + for (target = 0; target < buswidth; target++) { + sc_link = ((struct scsibus_softc *)dev)->sc_link[target][0]; + if ((sc_link != NULL)) { + /* got a device! run PPR */ + /*if (device == cpu) { + continue; + }*/ + if (mpt_ppr(mpt, sc_link, U320)) { + mpt->mpt_negotiated_speed[target] = U320; + continue; + } + + if (mpt_ppr(mpt, sc_link, U160)) { + mpt->mpt_negotiated_speed[target] = U160; + continue; + } + + if (mpt_ppr(mpt, sc_link, U80)) { + mpt->mpt_negotiated_speed[target] = U80; + continue; + } + + } /* sc_link */ + } /* for target */ + } /* if dev */ + } /* end for dev */ +} + /* * Complete attachment of hardware, include subdevices. */ @@ -167,6 +421,12 @@ mpt_attach(mpt_softc_t *mpt) mpt->verbose = 2; #endif (void) config_found(&mpt->mpt_dev, lptr, scsiprint); + + /* done attaching now walk targets and PPR them */ + /* FC does not do PPR */ + if (!mpt->is_fc) { + mpt_run_ppr(mpt); + } } int @@ -391,7 +651,7 @@ mpt_timeout(void *arg) struct scsi_link *linkp = xs->sc_link; mpt_softc_t *mpt = (void *) linkp->adapter_softc; uint32_t oseq; - int s; + int s, index; mpt_prt(mpt, "command timeout\n"); sc_print_addr(linkp); @@ -419,14 +679,11 @@ mpt_timeout(void *arg) if (mpt->verbose > 1) mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf); - /* XXX WHAT IF THE IOC IS STILL USING IT?? */ - /* XXX MU we should delay the call to mpt_free_request */ - req->xfer = NULL; - mpt_free_request(mpt, req); + for(index = 0; index < MPT_MAX_REQUESTS(mpt); index++) + if (req == &mpt->request_pool[index]) + break; - xs->error = XS_TIMEOUT; - xs->flags |= ITSDONE; - scsi_done(xs); + mpt_done(mpt, index); splx(s); } @@ -644,10 +901,20 @@ mpt_done(mpt_softc_t *mpt, uint32_t reply) break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + xs->error = XS_DRIVER_STUFFUP; + break; + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: + xs->error = XS_DRIVER_STUFFUP; + break; + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + /* XXX */ + xs->error = XS_DRIVER_STUFFUP; + break; + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: - /* XXX When in doubt, STUFFUP. */ + /* XXX */ xs->error = XS_DRIVER_STUFFUP; break; @@ -744,9 +1011,6 @@ mpt_run_xfer(mpt_softc_t *mpt, struct scsi_xfer *xs) else mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER; - if (cold && !(xs->sc_link->quirks & SDEV_NOWIDE)) - mpt_set_xfer_mode(mpt, xs); - mpt_check_xfer_settings(mpt, xs, mpt_req); /* Copy the SCSI command block into place. */ @@ -950,141 +1214,6 @@ mpt_run_xfer(mpt_softc_t *mpt, struct scsi_xfer *xs) return (COMPLETE); } -void -mpt_set_xfer_mode(mpt_softc_t *mpt, struct scsi_xfer *xs) -{ - fCONFIG_PAGE_SCSI_DEVICE_1 tmp; - - if (mpt->is_fc) { - /* - * SCSI transport settings don't make any sense for - * Fibre Channel; silently ignore the request. - */ - return; - } - - /* - * Always allow disconnect; we don't have a way to disable - * it right now, in any case. - */ - mpt->mpt_disc_enable |= (1 << xs->sc_link->target); - - if (xs->sc_link->quirks & SDEV_NOTAGS) - mpt->mpt_tag_enable &= ~(1 << xs->sc_link->target); - else - mpt->mpt_tag_enable |= (1 << xs->sc_link->target); - - tmp = mpt->mpt_dev_page1[xs->sc_link->target]; - - /* - * Set the wide/narrow parameter for the target. - */ - if (xs->sc_link->quirks & SDEV_NOWIDE) - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; - else { - tmp.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; - } - /* - * Set the synchronous parameters for the target. - * - * XXX If we request sync transfers, we just go ahead and - * XXX request the maximum available. We need finer control - * XXX in order to implement Domain Validation. - */ - tmp.RequestedParameters &= ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK | - MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK | - MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS | - MPI_SCSIDEVPAGE1_RP_IU); - if (!(xs->sc_link->quirks & SDEV_NOSYNC)) { - int factor, offset, np; - - factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff; - offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff; - np = 0; - if (factor < 0x9) { - /* Ultra320 */ - np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU; - } - if (factor < 0xa) { - /* at least Ultra160 */ - np |= MPI_SCSIDEVPAGE1_RP_DT; - } - np |= (factor << 8) | (offset << 16); - tmp.RequestedParameters |= np; - } - - if (mpt_write_cfg_page(mpt, xs->sc_link->target, &tmp.Header)) { - mpt_prt(mpt, "unable to write Device Page 1"); - return; - } - - if (mpt_read_cfg_page(mpt, xs->sc_link->target, &tmp.Header)) { - mpt_prt(mpt, "unable to read back Device Page 1"); - return; - } - - mpt->mpt_dev_page1[xs->sc_link->target] = tmp; - if (mpt->verbose > 1) { - mpt_prt(mpt, - "SPI Target %d Page 1: RequestedParameters %x Config %x", - xs->sc_link->target, - mpt->mpt_dev_page1[xs->sc_link->target].RequestedParameters, - mpt->mpt_dev_page1[xs->sc_link->target].Configuration); - } - - return; -} -#if 0 -static void -mpt_get_xfer_mode(mpt_softc_t *mpt, struct scsipi_periph *periph) -{ - fCONFIG_PAGE_SCSI_DEVICE_0 tmp; - struct scsipi_xfer_mode xm; - int period, offset; - - tmp = mpt->mpt_dev_page0[periph->periph_target]; - if (mpt_read_cfg_page(mpt, periph->periph_target, &tmp.Header)) { - mpt_prt(mpt, "unable to read Device Page 0"); - return; - } - - if (mpt->verbose > 1) { - mpt_prt(mpt, - "SPI Tgt %d Page 0: NParms %x Information %x", - periph->periph_target, - tmp.NegotiatedParameters, tmp.Information); - } - - xm.xm_target = periph->periph_target; - xm.xm_mode = 0; - - if (tmp.NegotiatedParameters & MPI_SCSIDEVPAGE0_NP_WIDE) - xm.xm_mode |= PERIPH_CAP_WIDE16; - - period = (tmp.NegotiatedParameters >> 8) & 0xff; - offset = (tmp.NegotiatedParameters >> 16) & 0xff; - if (offset) { - xm.xm_period = period; - xm.xm_offset = offset; - xm.xm_mode |= PERIPH_CAP_SYNC; - } - - /* - * Tagged queueing is all controlled by us; there is no - * other setting to query. - */ - if (mpt->mpt_tag_enable & (1 << periph->periph_target)) - xm.xm_mode |= PERIPH_CAP_TQING; - - /* - * We're going to deliver the async event, so clear the marker. - */ - mpt->mpt_report_xfer_mode &= ~(1 << periph->periph_target); - - scsipi_async_event(&mpt->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); -} -#endif /* scsipi_xfer_mode */ - static void mpt_ctlop(mpt_softc_t *mpt, void *vmsg, uint32_t reply) { @@ -1304,7 +1433,7 @@ mpt_check_xfer_settings(mpt_softc_t *mpt, struct scsi_xfer *xs, MSG_SCSI_IO_REQU */ return; } -#if 0 + /* * XXX never do these commands with tags. Should really be * in a higher layer. @@ -1313,7 +1442,7 @@ mpt_check_xfer_settings(mpt_softc_t *mpt, struct scsi_xfer *xs, MSG_SCSI_IO_REQU xs->cmd->opcode == TEST_UNIT_READY || xs->cmd->opcode == REQUEST_SENSE) return; -#endif + /* Set the queue behavior. */ if (mpt->is_fc || (mpt->mpt_tag_enable & (1 << xs->sc_link->target))) { mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; diff --git a/sys/dev/ic/mpt_openbsd.h b/sys/dev/ic/mpt_openbsd.h index 02da99b464f..c1d28d4a09c 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.2 2004/03/07 05:08:16 krw Exp $ */ +/* $OpenBSD: mpt_openbsd.h,v 1.3 2004/03/14 23:14:36 krw Exp $ */ /* $NetBSD: mpt_netbsd.h,v 1.2 2003/04/16 23:02:14 thorpej Exp $ */ /* @@ -214,6 +214,7 @@ typedef struct mpt_softc { fCONFIG_PAGE_SCSI_PORT_2 _port_page2; fCONFIG_PAGE_SCSI_DEVICE_0 _dev_page0[16]; fCONFIG_PAGE_SCSI_DEVICE_1 _dev_page1[16]; + uint16_t _negotiated_speed[16]; uint16_t _tag_enable; uint16_t _disc_enable; uint16_t _update_params0; @@ -225,6 +226,7 @@ typedef struct mpt_softc { #define mpt_port_page2 cfg.spi._port_page2 #define mpt_dev_page0 cfg.spi._dev_page0 #define mpt_dev_page1 cfg.spi._dev_page1 +#define mpt_negotiated_speed cfg.spi._negotiated_speed #define mpt_tag_enable cfg.spi._tag_enable #define mpt_disc_enable cfg.spi._disc_enable #define mpt_update_params0 cfg.spi._update_params0 |