diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 5f10cc67c6d0..61a57e3b2ab5 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -173,6 +173,15 @@ typedef enum { XPT_ATA_IO = 0x18 | XPT_FC_DEV_QUEUED, /* Execute the requested ATA I/O operation */ + XPT_GET_SIM_KNOB = 0x18, + /* + * Get SIM specific knob values. + */ + + XPT_SET_SIM_KNOB = 0x19, + /* + * Set SIM specific knob values. + */ /* HBA engine commands 0x20->0x2F */ XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY, /* HBA engine feature inquiry */ @@ -189,8 +198,12 @@ typedef enum { XPT_CONT_TARGET_IO = 0x33 | XPT_FC_DEV_QUEUED, /* Continue Host Target I/O Connection */ XPT_IMMED_NOTIFY = 0x34 | XPT_FC_QUEUED | XPT_FC_USER_CCB, - /* Notify Host Target driver of event */ + /* Notify Host Target driver of event (obsolete) */ XPT_NOTIFY_ACK = 0x35, + /* Acknowledgement of event (obsolete) */ + XPT_IMMEDIATE_NOTIFY = 0x36 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Notify Host Target driver of event */ + XPT_NOTIFY_ACKNOWLEDGE = 0x37 | XPT_FC_QUEUED | XPT_FC_USER_CCB, /* Acknowledgement of event */ /* Vendor Unique codes: 0x80->0x8F */ @@ -531,12 +544,14 @@ typedef enum { struct ccb_pathinq_settings_spi { u_int8_t ppr_options; }; + struct ccb_pathinq_settings_fc { u_int64_t wwnn; /* world wide node name */ u_int64_t wwpn; /* world wide port name */ u_int32_t port; /* 24 bit port id, if known */ u_int32_t bitrate; /* Mbps */ }; + struct ccb_pathinq_settings_sas { u_int32_t bitrate; /* Mbps */ }; @@ -678,6 +693,7 @@ struct ccb_relsim { * Definitions for the asynchronous callback CCB fields. */ typedef enum { + AC_CONTRACT = 0x1000,/* A contractual callback */ AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */ AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */ AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */ @@ -694,6 +710,26 @@ typedef enum { typedef void ac_callback_t (void *softc, u_int32_t code, struct cam_path *path, void *args); +/* + * Generic Asynchronous callbacks. + * + * Generic arguments passed bac which are then interpreted between a per-system + * contract number. + */ +#define AC_CONTRACT_DATA_MAX (128 - sizeof (u_int64_t)) +struct ac_contract { + u_int64_t contract_number; + u_int8_t contract_data[AC_CONTRACT_DATA_MAX]; +}; + +#define AC_CONTRACT_DEV_CHG 1 +struct ac_device_changed { + u_int64_t wwpn; + u_int32_t port; + target_id_t target; + u_int8_t arrived; +}; + /* Set Asynchronous Callback CCB */ struct ccb_setasync { struct ccb_hdr ccb_h; @@ -822,6 +858,50 @@ struct ccb_calc_geometry { u_int8_t secs_per_track; }; +/* + * Set or get SIM (and transport) specific knobs + */ + +#define KNOB_VALID_ADDRESS 0x1 +#define KNOB_VALID_ROLE 0x2 + + +#define KNOB_ROLE_NONE 0x0 +#define KNOB_ROLE_INITIATOR 0x1 +#define KNOB_ROLE_TARGET 0x2 +#define KNOB_ROLE_BOTH 0x3 + +struct ccb_sim_knob_settings_spi { + u_int valid; + u_int initiator_id; + u_int role; +}; + +struct ccb_sim_knob_settings_fc { + u_int valid; + u_int64_t wwnn; /* world wide node name */ + u_int64_t wwpn; /* world wide port name */ + u_int role; +}; + +struct ccb_sim_knob_settings_sas { + u_int valid; + u_int64_t wwnn; /* world wide node name */ + u_int role; +}; +#define KNOB_SETTINGS_SIZE 128 + +struct ccb_sim_knob { + struct ccb_hdr ccb_h; + union { + u_int valid; /* Which fields to honor */ + struct ccb_sim_knob_settings_spi spi; + struct ccb_sim_knob_settings_fc fc; + struct ccb_sim_knob_settings_sas sas; + char pad[KNOB_SETTINGS_SIZE]; + } xport_specific; +}; + /* * Rescan the given bus, or bus/target/lun */ @@ -847,6 +927,7 @@ struct ccb_en_lun { u_int8_t enable; }; +/* old, barely used immediate notify, binary compatibility */ struct ccb_immed_notify { struct ccb_hdr ccb_h; struct scsi_sense_data sense_data; @@ -861,6 +942,22 @@ struct ccb_notify_ack { u_int8_t event; /* Event flags */ }; +struct ccb_immediate_notify { + struct ccb_hdr ccb_h; + u_int tag_id; /* Tag for immediate notify */ + u_int seq_id; /* Tag for target of notify */ + u_int initiator_id; /* Initiator Identifier */ + u_int arg; /* Function specific */ +}; + +struct ccb_notify_acknowledge { + struct ccb_hdr ccb_h; + u_int tag_id; /* Tag for immediate notify */ + u_int seq_id; /* Tar for target of notify */ + u_int initiator_id; /* Initiator Identifier */ + u_int arg; /* Function specific */ +}; + /* HBA engine structures. */ typedef enum { @@ -935,6 +1032,7 @@ union ccb { struct ccb_dev_match cdm; struct ccb_trans_settings cts; struct ccb_calc_geometry ccg; + struct ccb_sim_knob knob; struct ccb_abort cab; struct ccb_resetbus crb; struct ccb_resetdev crd; @@ -944,6 +1042,8 @@ union ccb { struct ccb_en_lun cel; struct ccb_immed_notify cin; struct ccb_notify_ack cna; + struct ccb_immediate_notify cin1; + struct ccb_notify_acknowledge cna2; struct ccb_eng_inq cei; struct ccb_eng_exec cee; struct ccb_rescan crcn; diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index fe759e95de25..ea259668acf4 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -2565,6 +2565,10 @@ xpt_action_default(union ccb *start_ccb) case XPT_IMMED_NOTIFY: case XPT_NOTIFY_ACK: case XPT_RESET_BUS: + case XPT_IMMEDIATE_NOTIFY: + case XPT_NOTIFY_ACKNOWLEDGE: + case XPT_GET_SIM_KNOB: + case XPT_SET_SIM_KNOB: { struct cam_sim *sim; diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 1ad4e9157f85..a4a40a87accd 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -1,17 +1,17 @@ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -23,6 +23,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* @@ -64,51 +65,52 @@ __FBSDID("$FreeBSD$"); */ #define MBOX_DELAY_COUNT 1000000 / 100 -#define ISP_MARK_PORTDB(a, b) \ - isp_prt(isp, ISP_LOGSANCFG, "line %d: markportdb", __LINE__); \ - isp_mark_portdb(a, b) +#define ISP_MARK_PORTDB(a, b, c) \ + isp_prt(isp, ISP_LOGSANCFG, \ + "Chan %d ISP_MARK_PORTDB@LINE %d", b, __LINE__); \ + isp_mark_portdb(a, b, c) /* * Local static data */ -static const char fconf[] = - "PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n" - " database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)"; -static const char notresp[] = - "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d"; -static const char xact1[] = - "HBA attempted queued transaction with disconnect not set for %d.%d.%d"; -static const char xact2[] = - "HBA attempted queued transaction to target routine %d on target %d bus %d"; -static const char xact3[] = - "HBA attempted queued cmd for %d.%d.%d when queueing disabled"; -static const char pskip[] = - "SCSI phase skipped for target %d.%d.%d"; -static const char topology[] = - "HBA PortID 0x%06x N-Port Handle %d, Connection Topology '%s'"; -static const char ourwwn[] = - "HBA WWNN 0x%08x%08x HBA WWPN 0x%08x%08x"; -static const char finmsg[] = - "%d.%d.%d: FIN dl%d resid %d STS 0x%x SKEY %c XS_ERR=0x%x"; -static const char sc0[] = - "%s CHAN %d FTHRSH %d IID %d RESETD %d RETRYC %d RETRYD %d ASD 0x%x"; -static const char sc1[] = - "%s RAAN 0x%x DLAN 0x%x DDMAB 0x%x CDMAB 0x%x SELTIME %d MQD %d"; -static const char sc2[] = "%s CHAN %d TGT %d FLAGS 0x%x 0x%x/0x%x"; -static const char sc3[] = "Generated"; +static const char fconf[] = "Chan %d PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)"; +static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d"; +static const char xact1[] = "HBA attempted queued transaction with disconnect not set for %d.%d.%d"; +static const char xact2[] = "HBA attempted queued transaction to target routine %d on target %d bus %d"; +static const char xact3[] = "HBA attempted queued cmd for %d.%d.%d when queueing disabled"; +static const char pskip[] = "SCSI phase skipped for target %d.%d.%d"; +static const char topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x N-Port Handle %d, Connection '%s'"; +static const char finmsg[] = "%d.%d.%d: FIN dl%d resid %ld STS 0x%x SKEY %c XS_ERR=0x%x"; static const char sc4[] = "NVRAM"; -static const char bun[] = - "bad underrun for %d.%d (count %d, resid %d, status %s)"; +static const char bun[] = "bad underrun for %d.%d (count %d, resid %d, status %s)"; +static const char lipd[] = "Chan %d LIP destroyed %d active commands"; +static const char sacq[] = "unable to acquire scratch area"; + +static const uint8_t alpa_map[] = { + 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, + 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, + 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, + 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3, + 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, + 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, + 0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, + 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73, + 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, + 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, + 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, + 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, + 0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26, + 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, + 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00 +}; /* * Local function prototypes. */ static int isp_parse_async(ispsoftc_t *, uint16_t); -static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, - uint32_t *); -static void -isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); -static void +static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *); +static void isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); static void isp_parse_status_24xx(ispsoftc_t *, isp24xx_statusreq_t *, XS_T *, long *); static void isp_fastpost_complete(ispsoftc_t *, uint16_t); static int isp_mbox_continue(ispsoftc_t *); @@ -116,39 +118,37 @@ static void isp_scsi_init(ispsoftc_t *); static void isp_scsi_channel_init(ispsoftc_t *, int); static void isp_fibre_init(ispsoftc_t *); static void isp_fibre_init_2400(ispsoftc_t *); -static void isp_mark_portdb(ispsoftc_t *, int); -static int isp_plogx(ispsoftc_t *, uint16_t, uint32_t, int, int); +static void isp_mark_portdb(ispsoftc_t *, int, int); +static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int); static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); -static int isp_getpdb(ispsoftc_t *, uint16_t, isp_pdb_t *, int); -static uint64_t isp_get_portname(ispsoftc_t *, int, int); -static int isp_fclink_test(ispsoftc_t *, int); -static const char *ispfc_fw_statename(int); -static int isp_pdb_sync(ispsoftc_t *); -static int isp_scan_loop(ispsoftc_t *); -static int isp_gid_ft_sns(ispsoftc_t *); -static int isp_gid_ft_ct_passthru(ispsoftc_t *); -static int isp_scan_fabric(ispsoftc_t *); -static int isp_login_device(ispsoftc_t *, uint32_t, isp_pdb_t *, uint16_t *); -static int isp_register_fc4_type(ispsoftc_t *); -static int isp_register_fc4_type_24xx(ispsoftc_t *); -static uint16_t isp_nxt_handle(ispsoftc_t *, uint16_t); -static void isp_fw_state(ispsoftc_t *); +static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int); +static void isp_dump_chip_portdb(ispsoftc_t *, int, int); +static uint64_t isp_get_wwn(ispsoftc_t *, int, int, int); +static int isp_fclink_test(ispsoftc_t *, int, int); +static int isp_pdb_sync(ispsoftc_t *, int); +static int isp_scan_loop(ispsoftc_t *, int); +static int isp_gid_ft_sns(ispsoftc_t *, int); +static int isp_gid_ft_ct_passthru(ispsoftc_t *, int); +static int isp_scan_fabric(ispsoftc_t *, int); +static int isp_login_device(ispsoftc_t *, int, uint32_t, isp_pdb_t *, uint16_t *); +static int isp_register_fc4_type(ispsoftc_t *, int); +static int isp_register_fc4_type_24xx(ispsoftc_t *, int); +static uint16_t isp_nxt_handle(ispsoftc_t *, int, uint16_t); +static void isp_fw_state(ispsoftc_t *, int); static void isp_mboxcmd_qnw(ispsoftc_t *, mbreg_t *, int); static void isp_mboxcmd(ispsoftc_t *, mbreg_t *); -static void isp_update(ispsoftc_t *); -static void isp_update_bus(ispsoftc_t *, int); -static void isp_setdfltparm(ispsoftc_t *, int); -static void isp_setdfltfcparm(ispsoftc_t *); -static int isp_read_nvram(ispsoftc_t *); -static int isp_read_nvram_2400(ispsoftc_t *); +static void isp_spi_update(ispsoftc_t *, int); +static void isp_setdfltsdparm(ispsoftc_t *); +static void isp_setdfltfcparm(ispsoftc_t *, int); +static int isp_read_nvram(ispsoftc_t *, int); +static int isp_read_nvram_2400(ispsoftc_t *, uint8_t *); static void isp_rdnvram_word(ispsoftc_t *, int, uint16_t *); static void isp_rd_2400_nvram(ispsoftc_t *, uint32_t, uint32_t *); static void isp_parse_nvram_1020(ispsoftc_t *, uint8_t *); static void isp_parse_nvram_1080(ispsoftc_t *, int, uint8_t *); static void isp_parse_nvram_12160(ispsoftc_t *, int, uint8_t *); -static void isp_fix_nvram_wwns(ispsoftc_t *); static void isp_parse_nvram_2100(ispsoftc_t *, uint8_t *); static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); @@ -161,15 +161,20 @@ static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); */ void -isp_reset(ispsoftc_t *isp) +isp_reset(ispsoftc_t *isp, int do_load_defaults) { mbreg_t mbs; uint32_t code_org, val; int loops, i, dodnld = 1; - static const char *btype = "????"; + const char *btype = "????"; static const char dcrc[] = "Downloaded RISC Code Checksum Failure"; isp->isp_state = ISP_NILSTATE; + if (isp->isp_dead) { + isp_shutdown(isp); + ISP_DISABLE_INTS(isp); + return; + } /* * Basic types (SCSI, FibreChannel and PCI or SBus) @@ -181,51 +186,6 @@ isp_reset(ispsoftc_t *isp) * for SCSI adapters and do other settings for the 2100. */ - /* - * Get the current running firmware revision out of the - * chip before we hit it over the head (if this is our - * first time through). Note that we store this as the - * 'ROM' firmware revision- which it may not be. In any - * case, we don't really use this yet, but we may in - * the future. - */ - if (isp->isp_touched == 0) { - /* - * First see whether or not we're sitting in the ISP PROM. - * If we've just been reset, we'll have the string "ISP " - * spread through outgoing mailbox registers 1-3. We do - * this for PCI cards because otherwise we really don't - * know what state the card is in and we could hang if - * we try this command otherwise. - * - * For SBus cards, we just do this because they almost - * certainly will be running firmware by now. - */ - if (ISP_READ(isp, OUTMAILBOX1) != 0x4953 || - ISP_READ(isp, OUTMAILBOX2) != 0x5020 || - ISP_READ(isp, OUTMAILBOX3) != 0x2020) { - /* - * Just in case it was paused... - */ - if (IS_24XX(isp)) { - ISP_WRITE(isp, BIU2400_HCCR, - HCCR_2400_CMD_RELEASE); - } else { - ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); - } - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_ABOUT_FIRMWARE; - mbs.logval = MBLOGNONE; - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - isp->isp_romfw_rev[0] = mbs.param[1]; - isp->isp_romfw_rev[1] = mbs.param[2]; - isp->isp_romfw_rev[2] = mbs.param[3]; - } - } - isp->isp_touched = 1; - } - ISP_DISABLE_INTS(isp); /* @@ -244,17 +204,16 @@ isp_reset(ispsoftc_t *isp) } /* - * Set up DMA for the request and result queues. + * Set up DMA for the request and response queues. * * We do this now so we can use the request queue - * for a dma + * for dma to load firmware from. */ if (ISP_MBOXDMASETUP(isp) != 0) { isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); return; } - /* * Set up default request/response queue in-pointer/out-pointer * register indices. @@ -264,8 +223,6 @@ isp_reset(ispsoftc_t *isp) isp->isp_rqstoutrp = BIU2400_REQOUTP; isp->isp_respinrp = BIU2400_RSPINP; isp->isp_respoutrp = BIU2400_RSPOUTP; - isp->isp_atioinrp = BIU2400_ATIO_RSPINP; - isp->isp_atiooutrp = BIU2400_ATIO_REQINP; } else if (IS_23XX(isp)) { isp->isp_rqstinrp = BIU_REQINP; isp->isp_rqstoutrp = BIU_REQOUTP; @@ -310,6 +267,9 @@ isp_reset(ispsoftc_t *isp) case ISP_HA_FC_2400: btype = "2422"; break; + case ISP_HA_FC_2500: + btype = "2532"; + break; default: break; } @@ -326,11 +286,13 @@ isp_reset(ispsoftc_t *isp) ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); } } else if (IS_1240(isp)) { - sdparam *sdp = isp->isp_param; + sdparam *sdp; + btype = "1240"; isp->isp_clock = 60; + sdp = SDPARAM(isp, 0); sdp->isp_ultramode = 1; - sdp++; + sdp = SDPARAM(isp, 1); sdp->isp_ultramode = 1; /* * XXX: Should probably do some bus sensing. @@ -355,7 +317,7 @@ isp_reset(ispsoftc_t *isp) } else if (IS_ULTRA2(isp)) { static const char m[] = "bus %d is in %s Mode"; uint16_t l; - sdparam *sdp = isp->isp_param; + sdparam *sdp = SDPARAM(isp, 0); isp->isp_clock = 100; @@ -387,10 +349,10 @@ isp_reset(ispsoftc_t *isp) } if (IS_DUALBUS(isp)) { - sdp++; + sdp = SDPARAM(isp, 1); l = ISP_READ(isp, SXP_PINS_DIFF|SXP_BANK1_SELECT); l &= ISP1080_MODE_MASK; - switch(l) { + switch (l) { case ISP1080_LVD_MODE: sdp->isp_lvdmode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 1, "LVD"); @@ -412,7 +374,7 @@ isp_reset(ispsoftc_t *isp) } } } else { - sdparam *sdp = isp->isp_param; + sdparam *sdp = SDPARAM(isp, 0); i = ISP_READ(isp, BIU_CONF0) & BIU_CONF0_HW_MASK; switch (i) { default: @@ -509,7 +471,7 @@ isp_reset(ispsoftc_t *isp) /* * Hit the chip over the head with hammer, - * and give the ISP a chance to recover. + * and give it a chance to recover. */ if (IS_SCSI(isp)) { @@ -517,15 +479,13 @@ isp_reset(ispsoftc_t *isp) /* * A slight delay... */ - USEC_DELAY(100); + ISP_DELAY(100); /* * Clear data && control DMA engines. */ - ISP_WRITE(isp, CDMA_CONTROL, - DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); - ISP_WRITE(isp, DDMA_CONTROL, - DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); + ISP_WRITE(isp, CDMA_CONTROL, DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); + ISP_WRITE(isp, DDMA_CONTROL, DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); } else if (IS_24XX(isp)) { @@ -534,12 +494,12 @@ isp_reset(ispsoftc_t *isp) */ ISP_WRITE(isp, BIU2400_CSR, BIU2400_DMA_STOP|(3 << 4)); for (val = loops = 0; loops < 30000; loops++) { - USEC_DELAY(10); + ISP_DELAY(10); val = ISP_READ(isp, BIU2400_CSR); if ((val & BIU2400_DMA_ACTIVE) == 0) { break; } - } + } if (val & BIU2400_DMA_ACTIVE) { ISP_RESET0(isp); isp_prt(isp, ISP_LOGERR, "DMA Failed to Stop on Reset"); @@ -548,11 +508,10 @@ isp_reset(ispsoftc_t *isp) /* * Hold it in SOFT_RESET and STOP state for 100us. */ - ISP_WRITE(isp, BIU2400_CSR, - BIU2400_SOFT_RESET|BIU2400_DMA_STOP|(3 << 4)); - USEC_DELAY(100); + ISP_WRITE(isp, BIU2400_CSR, BIU2400_SOFT_RESET|BIU2400_DMA_STOP|(3 << 4)); + ISP_DELAY(100); for (loops = 0; loops < 10000; loops++) { - USEC_DELAY(5); + ISP_DELAY(5); val = ISP_READ(isp, OUTMAILBOX0); } for (val = loops = 0; loops < 500000; loops ++) { @@ -571,17 +530,14 @@ isp_reset(ispsoftc_t *isp) /* * A slight delay... */ - USEC_DELAY(100); + ISP_DELAY(100); /* * Clear data && control DMA engines. */ - ISP_WRITE(isp, CDMA2100_CONTROL, - DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); - ISP_WRITE(isp, TDMA2100_CONTROL, - DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); - ISP_WRITE(isp, RDMA2100_CONTROL, - DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); + ISP_WRITE(isp, CDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); + ISP_WRITE(isp, TDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); + ISP_WRITE(isp, RDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); } /* @@ -601,7 +557,7 @@ isp_reset(ispsoftc_t *isp) if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET)) break; } - USEC_DELAY(100); + ISP_DELAY(100); if (--loops < 0) { ISP_DUMPREGS(isp, "chip reset timed out"); ISP_RESET0(isp); @@ -629,17 +585,16 @@ isp_reset(ispsoftc_t *isp) ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RESET); } else { ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); - USEC_DELAY(100); + ISP_DELAY(100); ISP_WRITE(isp, BIU_SEMA, 0); } - /* * Post-RISC Reset stuff. */ if (IS_24XX(isp)) { for (val = loops = 0; loops < 5000000; loops++) { - USEC_DELAY(5); + ISP_DELAY(5); val = ISP_READ(isp, OUTMAILBOX0); if (val == 0) { break; @@ -663,8 +618,8 @@ isp_reset(ispsoftc_t *isp) ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST); ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST); } - if (SDPARAM(isp)->isp_ptisp) { - if (SDPARAM(isp)->isp_ultramode) { + if (SDPARAM(isp, 0)->isp_ptisp) { + if (SDPARAM(isp, 0)->isp_ultramode) { while (ISP_READ(isp, RISC_MTR) != 0x1313) { ISP_WRITE(isp, RISC_MTR, 0x1313); ISP_WRITE(isp, HCCR, HCCR_CMD_STEP); @@ -692,7 +647,12 @@ isp_reset(ispsoftc_t *isp) ISP_WRITE(isp, isp->isp_rqstoutrp, 0); ISP_WRITE(isp, isp->isp_respinrp, 0); ISP_WRITE(isp, isp->isp_respoutrp, 0); - + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_PRI_REQINP, 0); + ISP_WRITE(isp, BIU2400_PRI_REQOUTP, 0); + ISP_WRITE(isp, BIU2400_ATIO_RSPINP, 0); + ISP_WRITE(isp, BIU2400_ATIO_RSPOUTP, 0); + } /* * Do MD specific post initialization @@ -702,15 +662,15 @@ isp_reset(ispsoftc_t *isp) /* * Wait for everything to finish firing up. * - * Avoid doing this on the 2312 because you can generate a PCI + * Avoid doing this on early 2312s because you can generate a PCI * parity error (chip breakage). */ - if (IS_2312(isp)) { - USEC_DELAY(100); + if (IS_2312(isp) && isp->isp_revision < 2) { + ISP_DELAY(100); } else { loops = MBOX_DELAY_COUNT; while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) { - USEC_DELAY(100); + ISP_DELAY(100); if (--loops < 0) { ISP_RESET0(isp); isp_prt(isp, ISP_LOGERR, @@ -727,19 +687,25 @@ isp_reset(ispsoftc_t *isp) */ /* - * Do some sanity checking. + * Do some sanity checking by running a NOP command. + * If it succeeds, the ROM firmware is now running. */ - MEMZERO(&mbs, sizeof (mbs)); + ISP_MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_NO_OP; mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "NOP ommand failed (%x)", mbs.param[0]); ISP_RESET0(isp); return; } + /* + * Do some operational tests + */ + if (IS_SCSI(isp) || IS_24XX(isp)) { - MEMZERO(&mbs, sizeof (mbs)); + ISP_MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_MAILBOX_REG_TEST; mbs.param[1] = 0xdead; mbs.param[2] = 0xbeef; @@ -758,10 +724,7 @@ isp_reset(ispsoftc_t *isp) mbs.param[3] != 0xffff || mbs.param[4] != 0x1111 || mbs.param[5] != 0xa5a5) { ISP_RESET0(isp); - isp_prt(isp, ISP_LOGERR, - "Register Test Failed (0x%x 0x%x 0x%x 0x%x 0x%x)", - mbs.param[1], mbs.param[2], mbs.param[3], - mbs.param[4], mbs.param[5]); + isp_prt(isp, ISP_LOGERR, "Register Test Failed (0x%x 0x%x 0x%x 0x%x 0x%x)", mbs.param[1], mbs.param[2], mbs.param[3], mbs.param[4], mbs.param[5]); return; } @@ -776,8 +739,7 @@ isp_reset(ispsoftc_t *isp) * whether we have f/w at all and whether a config flag * has disabled our download. */ - if ((isp->isp_mdvec->dv_ispfw == NULL) || - (isp->isp_confopts & ISP_CFG_NORELOAD)) { + if ((isp->isp_mdvec->dv_ispfw == NULL) || (isp->isp_confopts & ISP_CFG_NORELOAD)) { dodnld = 0; } @@ -792,13 +754,6 @@ isp_reset(ispsoftc_t *isp) if (dodnld && IS_24XX(isp)) { const uint32_t *ptr = isp->isp_mdvec->dv_ispfw; - /* - * NB: Whatever you do do, do *not* issue the VERIFY FIRMWARE - * NB: command to the 2400 while loading new firmware. This - * NB: causes the new f/w to start and immediately crash back - * NB: to the ROM. - */ - /* * Keep loading until we run out of f/w. */ @@ -807,9 +762,7 @@ isp_reset(ispsoftc_t *isp) for (;;) { uint32_t la, wi, wl; - isp_prt(isp, ISP_LOGDEBUG0, - "load 0x%x words of code at load address 0x%x", - ptr[3], ptr[2]); + isp_prt(isp, ISP_LOGDEBUG0, "load 0x%x words of code at load address 0x%x", ptr[3], ptr[2]); wi = 0; la = ptr[2]; @@ -828,23 +781,31 @@ isp_reset(ispsoftc_t *isp) ISP_IOXPUT_32(isp, ptr[wi++], &cp[i]); wl--; } - MEMORYBARRIER(isp, SYNC_REQUEST, - 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_LOAD_RISC_RAM; - mbs.param[1] = la; - mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); - mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); - mbs.param[4] = nw >> 16; - mbs.param[5] = nw; - mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); - mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); - mbs.param[8] = la >> 16; + MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + ISP_MEMZERO(&mbs, sizeof (mbs)); + if (la < 0x10000 && nw < 0x10000) { + mbs.param[0] = MBOX_LOAD_RISC_RAM_2100; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + } else { + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw >> 16; + mbs.param[5] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + } mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "F/W Risc Ram Load Failed"); + isp_prt(isp, ISP_LOGERR, "F/W Risc Ram Load Failed"); ISP_RESET0(isp); return; } @@ -855,7 +816,7 @@ isp_reset(ispsoftc_t *isp) break; } ptr += ptr[3]; - } + } isp->isp_loaded_fw = 1; } else if (dodnld && IS_23XX(isp)) { const uint16_t *ptr = isp->isp_mdvec->dv_ispfw; @@ -868,17 +829,15 @@ isp_reset(ispsoftc_t *isp) for (;;) { uint32_t nxtaddr; - isp_prt(isp, ISP_LOGDEBUG0, - "load 0x%x words of code at load address 0x%x", - ptr[3], la); + isp_prt(isp, ISP_LOGDEBUG0, "load 0x%x words of code at load address 0x%x", ptr[3], la); wi = 0; wl = ptr[3]; while (wi < ptr[3]) { uint16_t *cp; - uint32_t nw; - + uint16_t nw; + nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 1; if (nw > wl) { nw = wl; @@ -891,22 +850,30 @@ isp_reset(ispsoftc_t *isp) ISP_IOXPUT_16(isp, ptr[wi++], &cp[i]); wl--; } - MEMORYBARRIER(isp, SYNC_REQUEST, - 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_LOAD_RISC_RAM; - mbs.param[1] = la; - mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); - mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); - mbs.param[4] = nw; - mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); - mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); - mbs.param[8] = la >> 16; + MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + ISP_MEMZERO(&mbs, sizeof (mbs)); + if (la < 0x10000) { + mbs.param[0] = MBOX_LOAD_RISC_RAM_2100; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + } else { + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + } mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "F/W Risc Ram Load Failed"); + isp_prt(isp, ISP_LOGERR, "F/W Risc Ram Load Failed"); ISP_RESET0(isp); return; } @@ -914,19 +881,6 @@ isp_reset(ispsoftc_t *isp) } if (!IS_2322(isp)) { - /* - * Verify that it downloaded correctly. - */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_VERIFY_CHECKSUM; - mbs.param[1] = code_org; - mbs.logval = MBLOGNONE; - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, dcrc); - ISP_RESET0(isp); - return; - } break; } @@ -951,41 +905,45 @@ isp_reset(ispsoftc_t *isp) union { const uint16_t *cp; uint16_t *np; - } u; - u.cp = isp->isp_mdvec->dv_ispfw; - isp->isp_mbxworkp = &u.np[1]; - isp->isp_mbxwrk0 = u.np[3] - 1; + } ucd; + ucd.cp = isp->isp_mdvec->dv_ispfw; + isp->isp_mbxworkp = &ucd.np[1]; + isp->isp_mbxwrk0 = ucd.np[3] - 1; isp->isp_mbxwrk1 = code_org + 1; - MEMZERO(&mbs, sizeof (mbs)); + ISP_MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_WRITE_RAM_WORD; mbs.param[1] = code_org; - mbs.param[2] = u.np[0]; + mbs.param[2] = ucd.np[0]; mbs.logval = MBLOGNONE; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "F/W download failed at word %d", - isp->isp_mbxwrk1 - code_org); + isp_prt(isp, ISP_LOGERR, "F/W download failed at word %d", isp->isp_mbxwrk1 - code_org); ISP_RESET0(isp); return; } - /* - * Verify that it downloaded correctly. - */ - MEMZERO(&mbs, sizeof (mbs)); + } else { + isp->isp_loaded_fw = 0; + isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download"); + } + + /* + * If we loaded firmware, verify its checksum + */ + if (isp->isp_loaded_fw) { + ISP_MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_VERIFY_CHECKSUM; - mbs.param[1] = code_org; - mbs.logval = MBLOGNONE; + if (IS_24XX(isp)) { + mbs.param[1] = code_org >> 16; + mbs.param[2] = code_org; + } else { + mbs.param[1] = code_org; + } isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGERR, dcrc); ISP_RESET0(isp); return; } - isp->isp_loaded_fw = 1; - } else { - isp->isp_loaded_fw = 0; - isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download"); } /* @@ -996,9 +954,7 @@ isp_reset(ispsoftc_t *isp) */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.timeout = 1000000; - mbs.param[0] = MBOX_EXEC_FIRMWARE; + MBSINIT(&mbs, MBOX_EXEC_FIRMWARE, MBLOGALL, 1000000); if (IS_24XX(isp)) { mbs.param[1] = code_org >> 16; mbs.param[2] = code_org; @@ -1007,6 +963,9 @@ isp_reset(ispsoftc_t *isp) } else { mbs.param[3] = 1; } + if (IS_25XX(isp)) { + mbs.ibits |= 0x10; + } } else if (IS_2322(isp)) { mbs.param[1] = code_org; if (isp->isp_loaded_fw) { @@ -1017,8 +976,6 @@ isp_reset(ispsoftc_t *isp) } else { mbs.param[1] = code_org; } - - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (IS_2322(isp) || IS_24XX(isp)) { if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { @@ -1029,37 +986,45 @@ isp_reset(ispsoftc_t *isp) /* * Give it a chance to finish starting up. + * Give the 24XX more time. */ - USEC_DELAY(250000); - - if (IS_SCSI(isp)) { + if (IS_24XX(isp)) { + ISP_DELAY(500000); /* - * Set CLOCK RATE, but only if asked to. + * Check to see if the 24XX firmware really started. */ - if (isp->isp_clock) { - mbs.param[0] = MBOX_SET_CLOCK_RATE; - mbs.param[1] = isp->isp_clock; - mbs.logval = MBLOGNONE; - isp_mboxcmd(isp, &mbs); - /* we will try not to care if this fails */ + if (mbs.param[1] == 0xdead) { + isp_prt(isp, ISP_LOGERR, "f/w didn't *really* start"); + ISP_RESET0(isp); + return; + } + } else { + ISP_DELAY(250000); + if (IS_SCSI(isp)) { + /* + * Set CLOCK RATE, but only if asked to. + */ + if (isp->isp_clock) { + mbs.param[0] = MBOX_SET_CLOCK_RATE; + mbs.param[1] = isp->isp_clock; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + /* we will try not to care if this fails */ + } } } - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_ABOUT_FIRMWARE; - mbs.logval = MBLOGALL; + /* + * Ask the chip for the current firmware version. + * This should prove that the new firmware is working. + */ + MBSINIT(&mbs, MBOX_ABOUT_FIRMWARE, MBLOGALL, 0); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { ISP_RESET0(isp); return; } - if (IS_24XX(isp) && mbs.param[1] == 0xdead) { - isp_prt(isp, ISP_LOGERR, "f/w didn't *really* start"); - ISP_RESET0(isp); - return; - } - /* * The SBus firmware that we are using apparently does not return * major, minor, micro revisions in the mailbox registers, which @@ -1075,17 +1040,15 @@ isp_reset(ispsoftc_t *isp) isp->isp_fwrev[1] = 37; #endif isp->isp_fwrev[2] = 0; - } + } } else { isp->isp_fwrev[0] = mbs.param[1]; isp->isp_fwrev[1] = mbs.param[2]; isp->isp_fwrev[2] = mbs.param[3]; } - isp_prt(isp, ISP_LOGALL, - "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d", - btype, isp->isp_revision, dodnld? "loaded" : "resident", - isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); + isp_prt(isp, ISP_LOGCONFIG, "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d", + btype, isp->isp_revision, dodnld? "loaded" : "resident", isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); if (IS_FC(isp)) { /* @@ -1097,50 +1060,24 @@ isp_reset(ispsoftc_t *isp) */ if ((ISP_FW_OLDER_THAN(isp, 1, 17, 1))) { #ifdef USE_SMALLER_2100_FIRMWARE - FCPARAM(isp)->isp_fwattr = ISP_FW_ATTR_SCCLUN; + isp->isp_fwattr = ISP_FW_ATTR_SCCLUN; #else - FCPARAM(isp)->isp_fwattr = 0; + isp->isp_fwattr = 0; #endif } else { - FCPARAM(isp)->isp_fwattr = mbs.param[6]; - isp_prt(isp, ISP_LOGDEBUG0, - "Firmware Attributes = 0x%x", mbs.param[6]); + isp->isp_fwattr = mbs.param[6]; + isp_prt(isp, ISP_LOGDEBUG0, "Firmware Attributes = 0x%x", mbs.param[6]); } - FCPARAM(isp)->isp_2klogin = 0; - FCPARAM(isp)->isp_sccfw = 0; - FCPARAM(isp)->isp_tmode = 0; - if (IS_24XX(isp)) { - FCPARAM(isp)->isp_2klogin = 1; - FCPARAM(isp)->isp_sccfw = 1; - FCPARAM(isp)->isp_tmode = 1; - } else { - if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { - FCPARAM(isp)->isp_sccfw = 1; - } - if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_2KLOGINS) { - FCPARAM(isp)->isp_2klogin = 1; - FCPARAM(isp)->isp_sccfw = 1; - } - if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) { - FCPARAM(isp)->isp_tmode = 1; - } - } - if (FCPARAM(isp)->isp_2klogin) { - isp_prt(isp, ISP_LOGCONFIG, "2K Logins Supported"); - } - } - - if (isp->isp_romfw_rev[0] || isp->isp_romfw_rev[1] || - isp->isp_romfw_rev[2]) { - isp_prt(isp, ISP_LOGCONFIG, "Last F/W revision was %d.%d.%d", - isp->isp_romfw_rev[0], isp->isp_romfw_rev[1], - isp->isp_romfw_rev[2]); + } else { +#ifndef ISP_TARGET_MODE + isp->isp_fwattr = ISP_FW_ATTR_TMODE; +#else + isp->isp_fwattr = 0; +#endif } if (!IS_24XX(isp)) { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_FIRMWARE_STATUS; - mbs.logval = MBLOGALL; + MBSINIT(&mbs, MBOX_GET_FIRMWARE_STATUS, MBLOGALL, 0); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { ISP_RESET0(isp); @@ -1150,9 +1087,26 @@ isp_reset(ispsoftc_t *isp) isp->isp_maxcmds = mbs.param[2]; } } - isp_prt(isp, ISP_LOGCONFIG, - "%d max I/O command limit set", isp->isp_maxcmds); - isp_fw_state(isp); + isp_prt(isp, ISP_LOGCONFIG, "%d max I/O command limit set", isp->isp_maxcmds); + + /* + * If we don't have Multi-ID f/w loaded, we need to restrict channels to one. + * Only make this check for non-SCSI cards (I'm not sure firmware attributes + * work for them). + */ + if (IS_FC(isp) && ISP_CAP_MULTI_ID(isp) == 0 && isp->isp_nchan > 1) { + isp_prt(isp, ISP_LOGWARN, "non-MULTIID f/w loaded, only can enable 1 of %d channels", isp->isp_nchan); + isp->isp_nchan = 1; + } + + for (i = 0; i < isp->isp_nchan; i++) { + isp_fw_state(isp, i); + } + if (isp->isp_dead) { + isp_shutdown(isp); + ISP_DISABLE_INTS(isp); + return; + } isp->isp_state = ISP_RESETSTATE; @@ -1184,24 +1138,27 @@ isp_reset(ispsoftc_t *isp) isp->isp_maxluns = 8; } } else { - if (FCPARAM(isp)->isp_sccfw) { + if (ISP_CAP_SCCFW(isp)) { isp->isp_maxluns = 16384; } else { isp->isp_maxluns = 16; } } - /* - * Must do this first to get defaults established. - */ - if (IS_SCSI(isp)) { - isp_setdfltparm(isp, 0); - if (IS_DUALBUS(isp)) { - isp_setdfltparm(isp, 1); - } - } else { - isp_setdfltfcparm(isp); - } + /* + * We get some default values established. As a side + * effect, NVRAM is read here (unless overriden by + * a configuration flag). + */ + if (do_load_defaults) { + if (IS_SCSI(isp)) { + isp_setdfltsdparm(isp); + } else { + for (i = 0; i < isp->isp_nchan; i++) { + isp_setdfltfcparm(isp, i); + } + } + } } /* @@ -1214,23 +1171,15 @@ void isp_init(ispsoftc_t *isp) { if (IS_FC(isp)) { - /* - * Do this *before* initializing the firmware. - */ - ISP_MARK_PORTDB(isp, 0); - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_NIL; - - if (isp->isp_role != ISP_ROLE_NONE) { - if (IS_24XX(isp)) { - isp_fibre_init_2400(isp); - } else { - isp_fibre_init(isp); - } + if (IS_24XX(isp)) { + isp_fibre_init_2400(isp); + } else { + isp_fibre_init(isp); } } else { isp_scsi_init(isp); } + GET_NANOTIME(&isp->isp_init_time); } static void @@ -1239,17 +1188,10 @@ isp_scsi_init(ispsoftc_t *isp) sdparam *sdp_chan0, *sdp_chan1; mbreg_t mbs; - sdp_chan0 = isp->isp_param; + sdp_chan0 = SDPARAM(isp, 0); sdp_chan1 = sdp_chan0; if (IS_DUALBUS(isp)) { - sdp_chan1++; - } - - /* - * If we have no role (neither target nor initiator), return. - */ - if (isp->isp_role == ISP_ROLE_NONE) { - return; + sdp_chan1 = SDPARAM(isp, 1); } /* First do overall per-card settings. */ @@ -1265,13 +1207,11 @@ isp_scsi_init(ispsoftc_t *isp) * Set Retry Delay and Count. * You set both channels at the same time. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_RETRY_COUNT; + MBSINIT(&mbs, MBOX_SET_RETRY_COUNT, MBLOGALL, 0); mbs.param[1] = sdp_chan0->isp_retry_count; mbs.param[2] = sdp_chan0->isp_retry_delay; mbs.param[6] = sdp_chan1->isp_retry_count; mbs.param[7] = sdp_chan1->isp_retry_delay; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1280,11 +1220,9 @@ isp_scsi_init(ispsoftc_t *isp) /* * Set ASYNC DATA SETUP time. This is very important. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; + MBSINIT(&mbs, MBOX_SET_ASYNC_DATA_SETUP_TIME, MBLOGALL, 0); mbs.param[1] = sdp_chan0->isp_async_data_setup; mbs.param[2] = sdp_chan1->isp_async_data_setup; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1293,15 +1231,13 @@ isp_scsi_init(ispsoftc_t *isp) /* * Set ACTIVE Negation State. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_ACT_NEG_STATE; + MBSINIT(&mbs, MBOX_SET_ACT_NEG_STATE, MBLOGNONE, 0); mbs.param[1] = (sdp_chan0->isp_req_ack_active_neg << 4) | (sdp_chan0->isp_data_line_active_neg << 5); mbs.param[2] = (sdp_chan1->isp_req_ack_active_neg << 4) | (sdp_chan1->isp_data_line_active_neg << 5); - mbs.logval = MBLOGNONE; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGERR, @@ -1318,11 +1254,9 @@ isp_scsi_init(ispsoftc_t *isp) /* * Set the Tag Aging limit */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_TAG_AGE_LIMIT; + MBSINIT(&mbs, MBOX_SET_TAG_AGE_LIMIT, MBLOGALL, 0); mbs.param[1] = sdp_chan0->isp_tag_aging; mbs.param[2] = sdp_chan1->isp_tag_aging; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGERR, "failed to set tag age limit (%d,%d)", @@ -1333,11 +1267,9 @@ isp_scsi_init(ispsoftc_t *isp) /* * Set selection timeout. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_SELECT_TIMEOUT; + MBSINIT(&mbs, MBOX_SET_SELECT_TIMEOUT, MBLOGALL, 0); mbs.param[1] = sdp_chan0->isp_selection_timeout; mbs.param[2] = sdp_chan1->isp_selection_timeout; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1353,56 +1285,48 @@ isp_scsi_init(ispsoftc_t *isp) */ if (IS_ULTRA2(isp) || IS_1240(isp)) { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_RES_QUEUE_A64; + MBSINIT(&mbs, MBOX_INIT_RES_QUEUE_A64, MBLOGALL, 0); mbs.param[1] = RESULT_QUEUE_LEN(isp); mbs.param[2] = DMA_WD1(isp->isp_result_dma); mbs.param[3] = DMA_WD0(isp->isp_result_dma); mbs.param[4] = 0; mbs.param[6] = DMA_WD3(isp->isp_result_dma); mbs.param[7] = DMA_WD2(isp->isp_result_dma); - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } isp->isp_residx = mbs.param[5]; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_REQ_QUEUE_A64; + MBSINIT(&mbs, MBOX_INIT_REQ_QUEUE_A64, MBLOGALL, 0); mbs.param[1] = RQUEST_QUEUE_LEN(isp); mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); mbs.param[5] = 0; mbs.param[6] = DMA_WD3(isp->isp_result_dma); mbs.param[7] = DMA_WD2(isp->isp_result_dma); - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } isp->isp_reqidx = isp->isp_reqodx = mbs.param[4]; } else { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_RES_QUEUE; + MBSINIT(&mbs, MBOX_INIT_RES_QUEUE, MBLOGALL, 0); mbs.param[1] = RESULT_QUEUE_LEN(isp); mbs.param[2] = DMA_WD1(isp->isp_result_dma); mbs.param[3] = DMA_WD0(isp->isp_result_dma); mbs.param[4] = 0; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } isp->isp_residx = mbs.param[5]; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_REQ_QUEUE; + MBSINIT(&mbs, MBOX_INIT_REQ_QUEUE, MBLOGALL, 0); mbs.param[1] = RQUEST_QUEUE_LEN(isp); mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); mbs.param[5] = 0; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1419,9 +1343,7 @@ isp_scsi_init(ispsoftc_t *isp) * to assume not for them. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_FW_FEATURES; - mbs.param[1] = 0; + MBSINIT(&mbs, MBOX_SET_FW_FEATURES, MBLOGALL, 0); if (IS_ULTRA2(isp)) mbs.param[1] |= FW_FEATURE_LVD_NOTIFY; #ifndef ISP_NO_RIO @@ -1433,7 +1355,6 @@ isp_scsi_init(ispsoftc_t *isp) #endif if (mbs.param[1] != 0) { uint16_t sfeat = mbs.param[1]; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGINFO, @@ -1441,35 +1362,29 @@ isp_scsi_init(ispsoftc_t *isp) } } - /* - * Let the outer layers decide whether to issue a SCSI bus reset. - */ isp->isp_state = ISP_INITSTATE; } static void -isp_scsi_channel_init(ispsoftc_t *isp, int channel) +isp_scsi_channel_init(ispsoftc_t *isp, int chan) { sdparam *sdp; mbreg_t mbs; int tgt; - sdp = isp->isp_param; - sdp += channel; + sdp = SDPARAM(isp, chan); /* * Set (possibly new) Initiator ID. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_INIT_SCSI_ID; - mbs.param[1] = (channel << 7) | sdp->isp_initiator_id; - mbs.logval = MBLOGALL; + MBSINIT(&mbs, MBOX_SET_INIT_SCSI_ID, MBLOGALL, 0); + mbs.param[1] = (chan << 7) | sdp->isp_initiator_id; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } - isp_prt(isp, ISP_LOGINFO, "Initiator ID is %d on Channel %d", - sdp->isp_initiator_id, channel); + isp_prt(isp, ISP_LOGINFO, "Chan %d Initiator ID is %d", + chan, sdp->isp_initiator_id); /* @@ -1505,9 +1420,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) */ sdp->isp_devparam[tgt].goal_flags = sdf = DPARM_DEFAULT; #endif - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_TARGET_PARAMS; - mbs.param[1] = (channel << 15) | (tgt << 8); + MBSINIT(&mbs, MBOX_SET_TARGET_PARAMS, MBLOGNONE, 0); + mbs.param[1] = (chan << 15) | (tgt << 8); mbs.param[2] = sdf; if ((sdf & DPARM_SYNC) == 0) { mbs.param[3] = 0; @@ -1518,18 +1432,15 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) } isp_prt(isp, ISP_LOGDEBUG0, "Initial Settings bus%d tgt%d flags 0x%x off 0x%x per 0x%x", - channel, tgt, mbs.param[2], mbs.param[3] >> 8, + chan, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); - mbs.logval = MBLOGNONE; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { sdf = DPARM_SAFE_DFLT; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_TARGET_PARAMS; - mbs.param[1] = (tgt << 8) | (channel << 15); + MBSINIT(&mbs, MBOX_SET_TARGET_PARAMS, MBLOGALL, 0); + mbs.param[1] = (tgt << 8) | (chan << 15); mbs.param[2] = sdf; mbs.param[3] = 0; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { continue; @@ -1549,12 +1460,10 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) */ sdp->isp_devparam[tgt].actv_flags = sdf & ~DPARM_TQING; for (lun = 0; lun < (int) isp->isp_maxluns; lun++) { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_DEV_QUEUE_PARAMS; - mbs.param[1] = (channel << 15) | (tgt << 8) | lun; + MBSINIT(&mbs, MBOX_SET_DEV_QUEUE_PARAMS, MBLOGALL, 0); + mbs.param[1] = (chan << 15) | (tgt << 8) | lun; mbs.param[2] = sdp->isp_max_queue_depth; mbs.param[3] = sdp->isp_devparam[tgt].exc_throttle; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; @@ -1563,8 +1472,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) } for (tgt = 0; tgt < MAX_TARGETS; tgt++) { if (sdp->isp_devparam[tgt].dev_refresh) { - isp->isp_sendmarker |= (1 << channel); - isp->isp_update |= (1 << channel); + sdp->sendmarker = 1; + sdp->update = 1; break; } } @@ -1580,11 +1489,17 @@ isp_fibre_init(ispsoftc_t *isp) isp_icb_t local, *icbp = &local; mbreg_t mbs; int ownloopid; - uint64_t nwwn, pwwn; - fcp = isp->isp_param; + /* + * We only support one channel on non-24XX cards + */ + fcp = FCPARAM(isp, 0); + if (fcp->role == ISP_ROLE_NONE) { + isp->isp_state = ISP_INITSTATE; + return; + } - MEMZERO(icbp, sizeof (*icbp)); + ISP_MEMZERO(icbp, sizeof (*icbp)); icbp->icb_version = ICB_VERSION1; icbp->icb_fwoptions = fcp->isp_fwoptions; @@ -1619,24 +1534,24 @@ isp_fibre_init(ispsoftc_t *isp) /* * Make sure that target role reflects into fwoptions. */ - if (isp->isp_role & ISP_ROLE_TARGET) { + if (fcp->role & ISP_ROLE_TARGET) { icbp->icb_fwoptions |= ICBOPT_TGT_ENABLE; } else { icbp->icb_fwoptions &= ~ICBOPT_TGT_ENABLE; } - if (isp->isp_role & ISP_ROLE_INITIATOR) { + if (fcp->role & ISP_ROLE_INITIATOR) { icbp->icb_fwoptions &= ~ICBOPT_INI_DISABLE; } else { icbp->icb_fwoptions |= ICBOPT_INI_DISABLE; } - icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; + icbp->icb_maxfrmlen = DEFAULT_FRAMESIZE(isp); if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { isp_prt(isp, ISP_LOGERR, "bad frame length (%d) from NVRAM- using %d", - fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN); + DEFAULT_FRAMESIZE(isp), ICB_DFLT_FRMLEN); icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; } icbp->icb_maxalloc = fcp->isp_maxalloc; @@ -1645,18 +1560,18 @@ isp_fibre_init(ispsoftc_t *isp) "bad maximum allocation (%d)- using 16", fcp->isp_maxalloc); icbp->icb_maxalloc = 16; } - icbp->icb_execthrottle = fcp->isp_execthrottle; + icbp->icb_execthrottle = DEFAULT_EXEC_THROTTLE(isp); if (icbp->icb_execthrottle < 1) { isp_prt(isp, ISP_LOGERR, - "bad execution throttle of %d- using 16", - fcp->isp_execthrottle); + "bad execution throttle of %d- using %d", + DEFAULT_EXEC_THROTTLE(isp), ICB_DFLT_THROTTLE); icbp->icb_execthrottle = ICB_DFLT_THROTTLE; } icbp->icb_retry_delay = fcp->isp_retry_delay; icbp->icb_retry_count = fcp->isp_retry_count; icbp->icb_hardaddr = fcp->isp_loopid; ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; - if (icbp->icb_hardaddr > 125) { + if (icbp->icb_hardaddr >= LOCAL_LOOP_LIM) { icbp->icb_hardaddr = 0; ownloopid = 0; } @@ -1672,7 +1587,7 @@ isp_fibre_init(ispsoftc_t *isp) /* * Right now we just set extended options to prefer point-to-point * over loop based upon some soft config options. - * + * * NB: for the 2300, ICBOPT_EXTENDED is required. */ if (IS_2200(isp) || IS_23XX(isp)) { @@ -1680,7 +1595,7 @@ isp_fibre_init(ispsoftc_t *isp) /* * Prefer or force Point-To-Point instead Loop? */ - switch(isp->isp_confopts & ISP_CFG_PORT_PREF) { + switch (isp->isp_confopts & ISP_CFG_PORT_PREF) { case ISP_CFG_NPORT: icbp->icb_xfwoptions |= ICBXOPT_PTP_2_LOOP; break; @@ -1695,7 +1610,26 @@ isp_fibre_init(ispsoftc_t *isp) break; } if (IS_2200(isp)) { + /* + * There seems to just be too much breakage here + * with RIO and Fast Posting- it probably actually + * works okay but this driver is messing it up. + * This card is really ancient by now, so let's + * just opt for safety and not use the feature. + */ +#if 0 + if (ISP_FW_NEWER_THAN(isp, 1, 17, 0)) { + icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT; + icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; + icbp->icb_racctimer = 4; + icbp->icb_idelaytimer = 8; + } else { + icbp->icb_fwoptions |= ICBOPT_FAST_POST; + } +#else + icbp->icb_xfwoptions &= ~ICBXOPT_RIO_16BIT; icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; +#endif } else { /* * QLogic recommends that FAST Posting be turned @@ -1704,8 +1638,7 @@ isp_fibre_init(ispsoftc_t *isp) * after a delay (ZIO). */ icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; - if ((fcp->isp_xfwoptions & ICBXOPT_TIMER_MASK) == - ICBXOPT_ZIO) { + if ((fcp->isp_xfwoptions & ICBXOPT_TIMER_MASK) == ICBXOPT_ZIO) { icbp->icb_xfwoptions |= ICBXOPT_ZIO; icbp->icb_idelaytimer = 10; } @@ -1733,12 +1666,10 @@ isp_fibre_init(ispsoftc_t *isp) * Turn on generate AE 8013 on all LIP Resets (2) * Disable LIP F7 switching (8) */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_FIRMWARE_OPTIONS; + MBSINIT(&mbs, MBOX_SET_FIRMWARE_OPTIONS, MBLOGALL, 0); mbs.param[1] = 0xb; mbs.param[2] = 0; mbs.param[3] = 0; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1747,25 +1678,23 @@ isp_fibre_init(ispsoftc_t *isp) icbp->icb_logintime = ICB_LOGIN_TOV; icbp->icb_lunetimeout = ICB_LUN_ENABLE_TOV; - nwwn = ISP_NODEWWN(isp); - pwwn = ISP_PORTWWN(isp); - if (nwwn && pwwn) { + if (fcp->isp_wwnn && fcp->isp_wwpn && (fcp->isp_wwnn >> 60) != 2) { icbp->icb_fwoptions |= ICBOPT_BOTH_WWNS; - MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, nwwn); - MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwnn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Node 0x%08x%08x Port 0x%08x%08x", - ((uint32_t) (nwwn >> 32)), - ((uint32_t) (nwwn & 0xffffffff)), - ((uint32_t) (pwwn >> 32)), - ((uint32_t) (pwwn & 0xffffffff))); - } else if (pwwn) { + ((uint32_t) (fcp->isp_wwnn >> 32)), + ((uint32_t) (fcp->isp_wwnn)), + ((uint32_t) (fcp->isp_wwpn >> 32)), + ((uint32_t) (fcp->isp_wwpn))); + } else if (fcp->isp_wwpn) { icbp->icb_fwoptions &= ~ICBOPT_BOTH_WWNS; - MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Port 0x%08x%08x", - ((uint32_t) (pwwn >> 32)), - ((uint32_t) (pwwn & 0xffffffff))); + ((uint32_t) (fcp->isp_wwpn >> 32)), + ((uint32_t) (fcp->isp_wwpn))); } else { isp_prt(isp, ISP_LOGERR, "No valid WWNs to use"); return; @@ -1787,30 +1716,31 @@ isp_fibre_init(ispsoftc_t *isp) icbp->icb_respaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_result_dma); icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); + if (FC_SCRATCH_ACQUIRE(isp, 0)) { + isp_prt(isp, ISP_LOGERR, sacq); + return; + } isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init: fwopt 0x%x xfwopt 0x%x zfwopt 0x%x", icbp->icb_fwoptions, icbp->icb_xfwoptions, icbp->icb_zfwoptions); - FC_SCRATCH_ACQUIRE(isp); isp_put_icb(isp, icbp, (isp_icb_t *)fcp->isp_scratch); /* * Init the firmware */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_FIRMWARE; + MBSINIT(&mbs, MBOX_INIT_FIRMWARE, MBLOGALL, 30000000); mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); mbs.logval = MBLOGALL; - mbs.timeout = 30 * 1000000; isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %p (%08x%08x)", fcp->isp_scratch, (uint32_t) ((uint64_t)fcp->isp_scdma >> 32), (uint32_t) fcp->isp_scdma); MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp)); isp_mboxcmd(isp, &mbs); - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, 0); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_print_bytes(isp, "isp_fibre_init", sizeof (*icbp), icbp); return; @@ -1831,65 +1761,71 @@ isp_fibre_init_2400(ispsoftc_t *isp) fcparam *fcp; isp_icb_2400_t local, *icbp = &local; mbreg_t mbs; - int ownloopid; - uint64_t nwwn, pwwn; + int chan; - fcp = isp->isp_param; + /* + * Check to see whether all channels have *some* kind of role + */ + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcp = FCPARAM(isp, chan); + if (fcp->role != ISP_ROLE_NONE) { + break; + } + } + if (chan == isp->isp_nchan) { + isp_prt(isp, ISP_LOGDEBUG0, "all %d channels with role 'none'", chan); + isp->isp_state = ISP_INITSTATE; + return; + } + + /* + * Start with channel 0. + */ + fcp = FCPARAM(isp, 0); /* * Turn on LIP F8 async event (1) */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SET_FIRMWARE_OPTIONS; + MBSINIT(&mbs, MBOX_SET_FIRMWARE_OPTIONS, MBLOGALL, 0); mbs.param[1] = 1; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } - /* - * XXX: This should be applied to icb- not fwoptions - */ - if (isp->isp_role & ISP_ROLE_TARGET) { - fcp->isp_fwoptions |= ICB2400_OPT1_TGT_ENABLE; + ISP_MEMZERO(icbp, sizeof (*icbp)); + icbp->icb_fwoptions1 = fcp->isp_fwoptions; + if (fcp->role & ISP_ROLE_TARGET) { + icbp->icb_fwoptions1 |= ICB2400_OPT1_TGT_ENABLE; } else { - fcp->isp_fwoptions &= ~ICB2400_OPT1_TGT_ENABLE; + icbp->icb_fwoptions1 &= ~ICB2400_OPT1_TGT_ENABLE; } - if (isp->isp_role & ISP_ROLE_INITIATOR) { - fcp->isp_fwoptions &= ~ICB2400_OPT1_INI_DISABLE; + if (fcp->role & ISP_ROLE_INITIATOR) { + icbp->icb_fwoptions1 &= ~ICB2400_OPT1_INI_DISABLE; } else { - fcp->isp_fwoptions |= ICB2400_OPT1_INI_DISABLE; + icbp->icb_fwoptions1 |= ICB2400_OPT1_INI_DISABLE; } - MEMZERO(icbp, sizeof (*icbp)); icbp->icb_version = ICB_VERSION1; - icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; - if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || - icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { - isp_prt(isp, ISP_LOGERR, - "bad frame length (%d) from NVRAM- using %d", - fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN); + icbp->icb_maxfrmlen = DEFAULT_FRAMESIZE(isp); + if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { + isp_prt(isp, ISP_LOGERR, "bad frame length (%d) from NVRAM- using %d", DEFAULT_FRAMESIZE(isp), ICB_DFLT_FRMLEN); icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; } - icbp->icb_execthrottle = fcp->isp_execthrottle; + icbp->icb_execthrottle = DEFAULT_EXEC_THROTTLE(isp); if (icbp->icb_execthrottle < 1) { - isp_prt(isp, ISP_LOGERR, - "bad execution throttle of %d- using 16", - fcp->isp_execthrottle); + isp_prt(isp, ISP_LOGERR, "bad execution throttle of %d- using %d", DEFAULT_EXEC_THROTTLE(isp), ICB_DFLT_THROTTLE); icbp->icb_execthrottle = ICB_DFLT_THROTTLE; } - if (isp->isp_role & ISP_ROLE_TARGET) { + if (icbp->icb_fwoptions1 & ICB2400_OPT1_TGT_ENABLE) { /* * Get current resource count */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_RESOURCE_COUNT; + MBSINIT(&mbs, MBOX_GET_RESOURCE_COUNT, MBLOGALL, 0); mbs.obits = 0x4cf; - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; @@ -1897,24 +1833,28 @@ isp_fibre_init_2400(ispsoftc_t *isp) icbp->icb_xchgcnt = mbs.param[3]; } - icbp->icb_fwoptions1 = fcp->isp_fwoptions; icbp->icb_hardaddr = fcp->isp_loopid; - ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; - if (icbp->icb_hardaddr > 125) { + if (icbp->icb_hardaddr >= LOCAL_LOOP_LIM) { icbp->icb_hardaddr = 0; - ownloopid = 0; - } - if (ownloopid) { - icbp->icb_fwoptions1 |= ICB2400_OPT1_HARD_ADDRESS; } + /* + * Force this on. + */ + icbp->icb_fwoptions1 |= ICB2400_OPT1_HARD_ADDRESS; + icbp->icb_fwoptions2 = fcp->isp_xfwoptions; - switch(isp->isp_confopts & ISP_CFG_PORT_PREF) { + switch (isp->isp_confopts & ISP_CFG_PORT_PREF) { +#if 0 case ISP_CFG_NPORT: + /* + * XXX: This causes the f/w to crash. + */ icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_2_LOOP; break; +#endif case ISP_CFG_NPORT_ONLY: icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_ONLY; @@ -1929,6 +1869,9 @@ isp_fibre_init_2400(ispsoftc_t *isp) break; } + /* force this on for now */ + icbp->icb_fwoptions2 |= ICB2400_OPT2_ZIO; + switch (icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK) { case ICB2400_OPT2_ZIO: case ICB2400_OPT2_ZIO1: @@ -1937,12 +1880,16 @@ isp_fibre_init_2400(ispsoftc_t *isp) case 0: break; default: - isp_prt(isp, ISP_LOGWARN, "bad value %x in fwopt2 timer field", - icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK); + isp_prt(isp, ISP_LOGWARN, "bad value %x in fwopt2 timer field", icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK); icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TIMER_MASK; break; } + /* + * We don't support FCTAPE, so clear it. + */ + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_FCTAPE; + icbp->icb_fwoptions3 = fcp->isp_zfwoptions; icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO; if (isp->isp_confopts & ISP_CFG_ONEGB) { @@ -1960,26 +1907,16 @@ isp_fibre_init_2400(ispsoftc_t *isp) } icbp->icb_logintime = ICB_LOGIN_TOV; - nwwn = ISP_NODEWWN(isp); - pwwn = ISP_PORTWWN(isp); - - if (nwwn && pwwn) { + if (fcp->isp_wwnn && fcp->isp_wwpn && (fcp->isp_wwnn >> 60) != 2) { icbp->icb_fwoptions1 |= ICB2400_OPT1_BOTH_WWNS; - MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, nwwn); - MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); - isp_prt(isp, ISP_LOGDEBUG1, - "Setting ICB Node 0x%08x%08x Port 0x%08x%08x", - ((uint32_t) (nwwn >> 32)), - ((uint32_t) (nwwn & 0xffffffff)), - ((uint32_t) (pwwn >> 32)), - ((uint32_t) (pwwn & 0xffffffff))); - } else if (pwwn) { + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwnn); + isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Node 0x%08x%08x Port 0x%08x%08x", ((uint32_t) (fcp->isp_wwnn >> 32)), ((uint32_t) (fcp->isp_wwnn)), + ((uint32_t) (fcp->isp_wwpn >> 32)), ((uint32_t) (fcp->isp_wwpn))); + } else if (fcp->isp_wwpn) { icbp->icb_fwoptions1 &= ~ICB2400_OPT1_BOTH_WWNS; - MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); - isp_prt(isp, ISP_LOGDEBUG1, - "Setting ICB Port 0x%08x%08x", - ((uint32_t) (pwwn >> 32)), - ((uint32_t) (pwwn & 0xffffffff))); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); + isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Node to be same as Port 0x%08x%08x", ((uint32_t) (fcp->isp_wwpn >> 32)), ((uint32_t) (fcp->isp_wwpn))); } else { isp_prt(isp, ISP_LOGERR, "No valid WWNs to use"); return; @@ -1988,8 +1925,7 @@ isp_fibre_init_2400(ispsoftc_t *isp) icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); if (icbp->icb_rqstqlen < 8) { - isp_prt(isp, ISP_LOGERR, "bad request queue length %d", - icbp->icb_rqstqlen); + isp_prt(isp, ISP_LOGERR, "bad request queue length %d", icbp->icb_rqstqlen); return; } icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp); @@ -2009,64 +1945,95 @@ isp_fibre_init_2400(ispsoftc_t *isp) icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); #ifdef ISP_TARGET_MODE - if (isp->isp_role & ISP_ROLE_TARGET) { - icbp->icb_atioqlen = RESULT_QUEUE_LEN(isp); - if (icbp->icb_atioqlen < 8) { - isp_prt(isp, ISP_LOGERR, "bad ATIO queue length %d", - icbp->icb_atioqlen); - return; - } - icbp->icb_atioqaddr[RQRSP_ADDR0015] = - DMA_WD0(isp->isp_atioq_dma); - icbp->icb_atioqaddr[RQRSP_ADDR1631] = - DMA_WD1(isp->isp_atioq_dma); - icbp->icb_atioqaddr[RQRSP_ADDR3247] = - DMA_WD2(isp->isp_atioq_dma); - icbp->icb_atioqaddr[RQRSP_ADDR4863] = - DMA_WD3(isp->isp_atioq_dma); - isp_prt(isp, ISP_LOGDEBUG0, - "isp_fibre_init_2400: atioq %04x%04x%04x%04x", - DMA_WD3(isp->isp_atioq_dma), DMA_WD2(isp->isp_atioq_dma), - DMA_WD1(isp->isp_atioq_dma), DMA_WD0(isp->isp_atioq_dma)); + /* unconditionally set up the ATIO queue if we support target mode */ + icbp->icb_atioqlen = RESULT_QUEUE_LEN(isp); + if (icbp->icb_atioqlen < 8) { + isp_prt(isp, ISP_LOGERR, "bad ATIO queue length %d", icbp->icb_atioqlen); + return; } + icbp->icb_atioqaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_atioq_dma); + isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: atioq %04x%04x%04x%04x", DMA_WD3(isp->isp_atioq_dma), DMA_WD2(isp->isp_atioq_dma), + DMA_WD1(isp->isp_atioq_dma), DMA_WD0(isp->isp_atioq_dma)); #endif - isp_prt(isp, ISP_LOGDEBUG0, - "isp_fibre_init_2400: fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x", - icbp->icb_fwoptions1, icbp->icb_fwoptions2, icbp->icb_fwoptions3); + isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x", icbp->icb_fwoptions1, icbp->icb_fwoptions2, icbp->icb_fwoptions3); - isp_prt(isp, ISP_LOGDEBUG0, - "isp_fibre_init_2400: rqst %04x%04x%04x%04x rsp %04x%04x%04x%04x", - DMA_WD3(isp->isp_rquest_dma), DMA_WD2(isp->isp_rquest_dma), - DMA_WD1(isp->isp_rquest_dma), DMA_WD0(isp->isp_rquest_dma), - DMA_WD3(isp->isp_result_dma), DMA_WD2(isp->isp_result_dma), + isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: rqst %04x%04x%04x%04x rsp %04x%04x%04x%04x", DMA_WD3(isp->isp_rquest_dma), DMA_WD2(isp->isp_rquest_dma), + DMA_WD1(isp->isp_rquest_dma), DMA_WD0(isp->isp_rquest_dma), DMA_WD3(isp->isp_result_dma), DMA_WD2(isp->isp_result_dma), DMA_WD1(isp->isp_result_dma), DMA_WD0(isp->isp_result_dma)); if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "isp_fibre_init_2400", sizeof (*icbp), - icbp); + isp_print_bytes(isp, "isp_fibre_init_2400", sizeof (*icbp), icbp); } - FC_SCRATCH_ACQUIRE(isp); + + if (FC_SCRATCH_ACQUIRE(isp, 0)) { + isp_prt(isp, ISP_LOGERR, sacq); + return; + } + ISP_MEMZERO(fcp->isp_scratch, ISP_FC_SCRLEN); isp_put_icb_2400(isp, icbp, fcp->isp_scratch); + /* + * Now fill in information about any additional channels + */ + if (isp->isp_nchan > 1) { + isp_icb_2400_vpinfo_t vpinfo, *vdst; + vp_port_info_t pi, *pdst; + size_t amt = 0; + uint8_t *off; + + vpinfo.vp_count = isp->isp_nchan - 1; + vpinfo.vp_global_options = 0; + off = fcp->isp_scratch; + off += ICB2400_VPINFO_OFF; + vdst = (isp_icb_2400_vpinfo_t *) off; + isp_put_icb_2400_vpinfo(isp, &vpinfo, vdst); + amt = ICB2400_VPINFO_OFF + sizeof (isp_icb_2400_vpinfo_t); + for (chan = 1; chan < isp->isp_nchan; chan++) { + fcparam *fcp2; + + ISP_MEMZERO(&pi, sizeof (pi)); + fcp2 = FCPARAM(isp, chan); + if (fcp2->role != ISP_ROLE_NONE) { + pi.vp_port_options = ICB2400_VPOPT_ENABLED; + if (fcp2->role & ISP_ROLE_INITIATOR) { + pi.vp_port_options |= ICB2400_VPOPT_INI_ENABLE; + } + if ((fcp2->role & ISP_ROLE_TARGET) == 0) { + pi.vp_port_options |= ICB2400_VPOPT_TGT_DISABLE; + } + MAKE_NODE_NAME_FROM_WWN(pi.vp_port_portname, fcp2->isp_wwpn); + MAKE_NODE_NAME_FROM_WWN(pi.vp_port_nodename, fcp2->isp_wwnn); + } + off = fcp->isp_scratch; + off += ICB2400_VPINFO_PORT_OFF(chan); + pdst = (vp_port_info_t *) off; + isp_put_vp_port_info(isp, &pi, pdst); + amt += ICB2400_VPOPT_WRITE_SIZE; + } + } /* * Init the firmware */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_FIRMWARE; + MBSINIT(&mbs, 0, MBLOGALL, 30000000); + if (isp->isp_nchan > 1) { + mbs.param[0] = MBOX_INIT_FIRMWARE_MULTI_ID; + } else { + mbs.param[0] = MBOX_INIT_FIRMWARE; + } mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - mbs.logval = MBLOGALL; - mbs.timeout = 30 * 1000000; - isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %04x%04x%04x%04x", - DMA_WD3(fcp->isp_scdma), DMA_WD2(fcp->isp_scdma), - DMA_WD1(fcp->isp_scdma), DMA_WD0(fcp->isp_scdma)); + isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %04x%04x%04x%04x", DMA_WD3(fcp->isp_scdma), DMA_WD2(fcp->isp_scdma), DMA_WD1(fcp->isp_scdma), DMA_WD0(fcp->isp_scdma)); MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp)); isp_mboxcmd(isp, &mbs); - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, 0); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -2081,30 +2048,40 @@ isp_fibre_init_2400(ispsoftc_t *isp) } static void -isp_mark_portdb(ispsoftc_t *isp, int onprobation) +isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition) { - fcparam *fcp = (fcparam *) isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); int i; + if (chan < 0 || chan >= isp->isp_nchan) { + isp_prt(isp, ISP_LOGWARN, "isp_mark_portdb: bad channel %d", chan); + return; + } for (i = 0; i < MAX_FC_TARG; i++) { - if (onprobation == 0) { - MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); + if (fcp->portdb[i].target_mode) { + if (disposition < 0) { + isp_prt(isp, ISP_LOGTINFO, "isp_mark_portdb: Chan %d zeroing handle 0x" "%04x port 0x%06x", chan, + fcp->portdb[i].handle, fcp->portdb[i].portid); + ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); + } + continue; + } + if (disposition == 0) { + ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); } else { switch (fcp->portdb[i].state) { case FC_PORTDB_STATE_CHANGED: case FC_PORTDB_STATE_PENDING_VALID: case FC_PORTDB_STATE_VALID: case FC_PORTDB_STATE_PROBATIONAL: - fcp->portdb[i].state = - FC_PORTDB_STATE_PROBATIONAL; + fcp->portdb[i].state = FC_PORTDB_STATE_PROBATIONAL; break; case FC_PORTDB_STATE_ZOMBIE: break; case FC_PORTDB_STATE_NIL: default: - MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); - fcp->portdb[i].state = - FC_PORTDB_STATE_NIL; + ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); + fcp->portdb[i].state = FC_PORTDB_STATE_NIL; break; } } @@ -2116,14 +2093,18 @@ isp_mark_portdb(ispsoftc_t *isp, int onprobation) * or via FABRIC LOGIN/FABRIC LOGOUT for other cards. */ static int -isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) +isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, + int flags, int gs) { mbreg_t mbs; uint8_t q[QENTRY_LEN]; isp_plogx_t *plp; + fcparam *fcp; uint8_t *scp; uint32_t sst, parm1; - int rval; + int rval, lev; + const char *msg; + char buf[64]; if (!IS_24XX(isp)) { int action = flags & PLOGX_FLG_CMD_MASK; @@ -2136,12 +2117,13 @@ isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) } } - MEMZERO(q, QENTRY_LEN); + ISP_MEMZERO(q, QENTRY_LEN); plp = (isp_plogx_t *) q; plp->plogx_header.rqs_entry_count = 1; plp->plogx_header.rqs_entry_type = RQSTYPE_LOGIN; plp->plogx_handle = 0xffffffff; plp->plogx_nphdl = handle; + plp->plogx_vphdl = chan; plp->plogx_portlo = portid; plp->plogx_rspsz_porthi = (portid >> 16) & 0xff; plp->plogx_flags = flags; @@ -2151,21 +2133,21 @@ isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) } if (gs == 0) { - FC_SCRATCH_ACQUIRE(isp); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } } - scp = FCPARAM(isp)->isp_scratch; + fcp = FCPARAM(isp, chan); + scp = fcp->isp_scratch; isp_put_plogx(isp, plp, (isp_plogx_t *) scp); - - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(FCPARAM(isp)->isp_scdma); - mbs.param[3] = DMA_WD0(FCPARAM(isp)->isp_scdma); - mbs.param[6] = DMA_WD3(FCPARAM(isp)->isp_scdma); - mbs.param[7] = DMA_WD2(FCPARAM(isp)->isp_scdma); - mbs.timeout = 500000; - mbs.logval = MBLOGALL; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { @@ -2183,8 +2165,9 @@ isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) rval = 0; goto out; } else if (plp->plogx_status != PLOGX_STATUS_IOCBERR) { - isp_prt(isp, ISP_LOGWARN, "status 0x%x on port login IOCB", - plp->plogx_status); + isp_prt(isp, ISP_LOGWARN, + "status 0x%x on port login IOCB chanel %d", + plp->plogx_status, chan); rval = -1; goto out; } @@ -2193,73 +2176,83 @@ isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) parm1 = plp->plogx_ioparm[1].lo16 | (plp->plogx_ioparm[1].hi16 << 16); rval = -1; + lev = ISP_LOGERR; + msg = NULL; switch (sst) { case PLOGX_IOCBERR_NOLINK: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no link"); + msg = "no link"; break; case PLOGX_IOCBERR_NOIOCB: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no IOCB buffer"); + msg = "no IOCB buffer"; break; case PLOGX_IOCBERR_NOXGHG: - isp_prt(isp, ISP_LOGERR, - "PLOGX failed- no Exchange Control Block"); + msg = "no Exchange Control Block"; break; case PLOGX_IOCBERR_FAILED: - isp_prt(isp, ISP_LOGERR, - "PLOGX(0x%x) of Port 0x%06x failed: reason 0x%x (last LOGIN" - " state 0x%x)", flags, portid, parm1 & 0xff, - (parm1 >> 8) & 0xff); + ISP_SNPRINTF(buf, sizeof (buf), + "reason 0x%x (last LOGIN state 0x%x)", + parm1 & 0xff, (parm1 >> 8) & 0xff); + msg = buf; break; case PLOGX_IOCBERR_NOFABRIC: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no fabric"); + msg = "no fabric"; break; case PLOGX_IOCBERR_NOTREADY: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- f/w not ready"); + msg = "firmware not ready"; break; case PLOGX_IOCBERR_NOLOGIN: - isp_prt(isp, ISP_LOGERR, - "PLOGX failed- not logged in (last LOGIN state 0x%x)", + ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)", parm1); + msg = buf; rval = MBOX_NOT_LOGGED_IN; break; case PLOGX_IOCBERR_REJECT: - isp_prt(isp, ISP_LOGERR, "PLOGX failed: LS_RJT = 0x%x", parm1); + ISP_SNPRINTF(buf, sizeof (buf), "LS_RJT = 0x%x", parm1); + msg = buf; break; case PLOGX_IOCBERR_NOPCB: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no PCB allocated"); + msg = "no PCB allocated"; break; case PLOGX_IOCBERR_EINVAL: - isp_prt(isp, ISP_LOGERR, - "PLOGX failed: invalid parameter at offset 0x%x", parm1); + ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x", + parm1); + msg = buf; break; case PLOGX_IOCBERR_PORTUSED: - isp_prt(isp, ISP_LOGDEBUG0, - "portid 0x%x already logged in with N-port handle 0x%x", - portid, parm1); - rval = MBOX_PORT_ID_USED | (handle << 16); + lev = ISP_LOGSANCFG|ISP_LOGDEBUG0; + ISP_SNPRINTF(buf, sizeof (buf), + "already logged in with N-Port handle 0x%x", parm1); + msg = buf; + rval = MBOX_PORT_ID_USED | (parm1 << 16); break; case PLOGX_IOCBERR_HNDLUSED: - isp_prt(isp, ISP_LOGDEBUG0, - "N-port handle 0x%x already used for portid 0x%x", - handle, parm1); + lev = ISP_LOGSANCFG|ISP_LOGDEBUG0; + ISP_SNPRINTF(buf, sizeof (buf), + "handle already used for PortID 0x%06x", parm1); + msg = buf; rval = MBOX_LOOP_ID_USED; break; case PLOGX_IOCBERR_NOHANDLE: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no handle allocated"); + msg = "no handle allocated"; break; case PLOGX_IOCBERR_NOFLOGI: - isp_prt(isp, ISP_LOGERR, "PLOGX failed- no FLOGI_ACC"); + msg = "no FLOGI_ACC"; break; default: - isp_prt(isp, ISP_LOGERR, "status %x from %x", plp->plogx_status, - flags); - rval = -1; + ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", + plp->plogx_status, flags); + msg = buf; break; } + if (msg) { + isp_prt(isp, ISP_LOGERR, + "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", + chan, portid, handle, msg); + } out: if (gs == 0) { - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); } return (rval); } @@ -2269,9 +2262,8 @@ isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid) { mbreg_t mbs; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGIN; - if (FCPARAM(isp)->isp_2klogin) { + MBSINIT(&mbs, MBOX_FABRIC_LOGIN, MBLOGNONE, 500000); + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = handle; mbs.ibits = (1 << 10); } else { @@ -2286,13 +2278,13 @@ isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid) switch (mbs.param[0]) { case MBOX_PORT_ID_USED: isp_prt(isp, ISP_LOGDEBUG0, - "isp_plogi_old: portid 0x%06x already logged in as %u", + "isp_port_login: portid 0x%06x already logged in as %u", portid, mbs.param[1]); return (MBOX_PORT_ID_USED | (mbs.param[1] << 16)); case MBOX_LOOP_ID_USED: isp_prt(isp, ISP_LOGDEBUG0, - "isp_plogi_old: handle %u in use for port id 0x%02xXXXX", + "isp_port_login: handle 0x%04x in use for port id 0x%02xXXXX", handle, mbs.param[1] & 0xff); return (MBOX_LOOP_ID_USED); @@ -2301,18 +2293,18 @@ isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid) case MBOX_COMMAND_ERROR: isp_prt(isp, ISP_LOGINFO, - "isp_plogi_old: error 0x%x in PLOGI to port 0x%06x", + "isp_port_login: error 0x%x in PLOGI to port 0x%06x", mbs.param[1], portid); return (MBOX_COMMAND_ERROR); case MBOX_ALL_IDS_USED: isp_prt(isp, ISP_LOGINFO, - "isp_plogi_old: all IDs used for fabric login"); + "isp_port_login: all IDs used for fabric login"); return (MBOX_ALL_IDS_USED); default: isp_prt(isp, ISP_LOGINFO, - "isp_plogi_old: error 0x%x on port login of 0x%06x@0x%0x", + "isp_port_login: error 0x%x on port login of 0x%06x@0x%0x", mbs.param[0], portid, handle); return (mbs.param[0]); } @@ -2323,38 +2315,34 @@ isp_port_logout(ispsoftc_t *isp, uint16_t handle, uint32_t portid) { mbreg_t mbs; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGOUT; - if (FCPARAM(isp)->isp_2klogin) { + MBSINIT(&mbs, MBOX_FABRIC_LOGOUT, MBLOGNONE, 500000); + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = handle; mbs.ibits = (1 << 10); } else { mbs.param[1] = handle << 8; } - mbs.logval = MBLOGNONE; - mbs.timeout = 100000; isp_mboxcmd(isp, &mbs); return (mbs.param[0] == MBOX_COMMAND_COMPLETE? 0 : mbs.param[0]); } static int -isp_getpdb(ispsoftc_t *isp, uint16_t id, isp_pdb_t *pdb, int dolock) +isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) { - fcparam *fcp = (fcparam *) isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); mbreg_t mbs; union { isp_pdb_21xx_t fred; isp_pdb_24xx_t bill; } un; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_PORT_DB; + MBSINIT(&mbs, MBOX_GET_PORT_DB, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR, 250000); if (IS_24XX(isp)) { - mbs.ibits = 0x3ff; + mbs.ibits = (1 << 9)|(1 << 10); mbs.param[1] = id; - } else if (FCPARAM(isp)->isp_2klogin) { + mbs.param[9] = chan; + } else if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = id; - mbs.ibits = (1 << 10); } else { mbs.param[1] = id << 8; } @@ -2362,68 +2350,111 @@ isp_getpdb(ispsoftc_t *isp, uint16_t id, isp_pdb_t *pdb, int dolock) mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - mbs.timeout = 250000; - mbs.logval = MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR; if (dolock) { - FC_SCRATCH_ACQUIRE(isp); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } } MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (un)); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { if (dolock) { - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); } - return (-1); + return (mbs.param[0]); } if (IS_24XX(isp)) { isp_get_pdb_24xx(isp, fcp->isp_scratch, &un.bill); pdb->handle = un.bill.pdb_handle; pdb->s3_role = un.bill.pdb_prli_svc3; pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); - MEMCPY(pdb->portname, un.bill.pdb_portname, 8); - MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); + ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); + ISP_MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Port 0x%06x flags 0x%x curstate %x", + chan, pdb->portid, un.bill.pdb_flags, + un.bill.pdb_curstate); + if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || + un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) { + mbs.param[0] = MBOX_NOT_LOGGED_IN; + if (dolock) { + FC_SCRATCH_RELEASE(isp, chan); + } + return (mbs.param[0]); + } } else { isp_get_pdb_21xx(isp, fcp->isp_scratch, &un.fred); pdb->handle = un.fred.pdb_loopid; pdb->s3_role = un.fred.pdb_prli_svc3; pdb->portid = BITS2WORD(un.fred.pdb_portid_bits); - MEMCPY(pdb->portname, un.fred.pdb_portname, 8); - MEMCPY(pdb->nodename, un.fred.pdb_nodename, 8); + ISP_MEMCPY(pdb->portname, un.fred.pdb_portname, 8); + ISP_MEMCPY(pdb->nodename, un.fred.pdb_nodename, 8); } if (dolock) { - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); } return (0); } -static uint64_t -isp_get_portname(ispsoftc_t *isp, int loopid, int nodename) +static void +isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock) { - uint64_t wwn = (uint64_t) -1; + isp_pdb_t pdb; + int lim, loopid; + + if (ISP_CAP_2KLOGIN(isp)) { + lim = NPH_MAX_2K; + } else { + lim = NPH_MAX; + } + for (loopid = 0; loopid != lim; loopid++) { + if (isp_getpdb(isp, chan, loopid, &pdb, dolock)) { + continue; + } + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGINFO, "Chan %d Loopid 0x%04x " + "PortID 0x%06x WWPN 0x%02x%02x%02x%02x%02x%02x%02x%02x", + chan, loopid, pdb.portid, pdb.portname[0], pdb.portname[1], + pdb.portname[2], pdb.portname[3], pdb.portname[4], + pdb.portname[5], pdb.portname[6], pdb.portname[7]); + } +} + +static uint64_t +isp_get_wwn(ispsoftc_t *isp, int chan, int loopid, int nodename) +{ + uint64_t wwn = INI_NONE; + fcparam *fcp = FCPARAM(isp, chan); mbreg_t mbs; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_PORT_NAME; - if (FCPARAM(isp)->isp_2klogin || IS_24XX(isp)) { + if (fcp->isp_fwstate < FW_READY || + fcp->isp_loopstate < LOOP_PDB_RCVD) { + return (wwn); + } + MBSINIT(&mbs, MBOX_GET_PORT_NAME, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR, 500000); + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = loopid; mbs.ibits = (1 << 10); if (nodename) { mbs.param[10] = 1; } + if (ISP_CAP_MULTI_ID(isp)) { + mbs.ibits |= (1 << 9); + mbs.param[9] = chan; + } } else { mbs.param[1] = loopid << 8; if (nodename) { mbs.param[1] |= 1; } } - mbs.logval = MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return (wwn); } if (IS_24XX(isp)) { wwn = - (((uint64_t)(mbs.param[2] >> 8)) << 56) | + (((uint64_t)(mbs.param[2] >> 8)) << 56) | (((uint64_t)(mbs.param[2] & 0xff)) << 48) | (((uint64_t)(mbs.param[3] >> 8)) << 40) | (((uint64_t)(mbs.param[3] & 0xff)) << 32) | @@ -2450,27 +2481,20 @@ isp_get_portname(ispsoftc_t *isp, int loopid, int nodename) */ static int -isp_fclink_test(ispsoftc_t *isp, int usdelay) +isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay) { - static const char *toponames[] = { - "Private Loop", - "FL Port", - "N-Port to N-Port", - "F Port", - "F Port (no FLOGI_ACC response)" - }; mbreg_t mbs; - int count, check_for_fabric; + int count, check_for_fabric, r; uint8_t lwfs; int loopid; fcparam *fcp; fcportdb_t *lp; isp_pdb_t pdb; - fcp = isp->isp_param; + fcp = FCPARAM(isp, chan); - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Entry"); - ISP_MARK_PORTDB(isp, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d FC Link Test Entry", chan); + ISP_MARK_PORTDB(isp, chan, 1); /* * Wait up to N microseconds for F/W to go to a ready state. @@ -2483,12 +2507,9 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) NANOTIME_T hra, hrb; GET_NANOTIME(&hra); - isp_fw_state(isp); + isp_fw_state(isp, chan); if (lwfs != fcp->isp_fwstate) { - isp_prt(isp, ISP_LOGCONFIG|ISP_LOGSANCFG, - "Firmware State <%s->%s>", - ispfc_fw_statename((int)lwfs), - ispfc_fw_statename((int)fcp->isp_fwstate)); + isp_prt(isp, ISP_LOGCONFIG|ISP_LOGSANCFG, "Chan %d Firmware State <%s->%s>", chan, isp_fc_fw_statename((int)lwfs), isp_fc_fw_statename((int)fcp->isp_fwstate)); lwfs = fcp->isp_fwstate; } if (fcp->isp_fwstate == FW_READY) { @@ -2502,10 +2523,7 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) */ enano = NANOTIME_SUB(&hrb, &hra); - isp_prt(isp, ISP_LOGDEBUG1, - "usec%d: 0x%lx->0x%lx enano 0x%x%08x", - count, (long) GET_NANOSEC(&hra), (long) GET_NANOSEC(&hrb), - (uint32_t)(enano >> 32), (uint32_t)(enano & 0xffffffff)); + isp_prt(isp, ISP_LOGDEBUG1, "usec%d: 0x%lx->0x%lx enano 0x%x%08x", count, (long) GET_NANOSEC(&hra), (long) GET_NANOSEC(&hrb), (uint32_t)(enano >> 32), (uint32_t)(enano)); /* * If the elapsed time is less than 1 millisecond, @@ -2520,12 +2538,12 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) count += 1000; enano = (1000 * 1000) - enano; while (enano > (uint64_t) 4000000000U) { - USEC_SLEEP(isp, 4000000); + ISP_SLEEP(isp, 4000000); enano -= (uint64_t) 4000000000U; } wrk = enano; wrk /= 1000; - USEC_SLEEP(isp, wrk); + ISP_SLEEP(isp, wrk); } else { while (enano > (uint64_t) 4000000000U) { count += 4000000; @@ -2536,27 +2554,31 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) } } + + /* * If we haven't gone to 'ready' state, return. */ if (fcp->isp_fwstate != FW_READY) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fclink_test: not at FW_READY state"); + isp_prt(isp, ISP_LOGSANCFG, "%s: chan %d not at FW_READY state", __func__, chan); return (-1); } /* * Get our Loop ID and Port ID. */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_LOOP_ID; - mbs.logval = MBLOGALL; + MBSINIT(&mbs, MBOX_GET_LOOP_ID, MBLOGALL, 0); + if (ISP_CAP_MULTI_ID(isp)) { + mbs.param[9] = chan; + mbs.ibits = (1 << 9); + mbs.obits = (1 << 7); + } isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return (-1); } - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { fcp->isp_loopid = mbs.param[1]; } else { fcp->isp_loopid = mbs.param[1] & 0xff; @@ -2583,21 +2605,52 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) } else { check_for_fabric = 0; } - } else if (fcp->isp_topo == TOPO_FL_PORT || - fcp->isp_topo == TOPO_F_PORT) { + } else if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_F_PORT) { check_for_fabric = 1; } else { check_for_fabric = 0; } - if (IS_24XX(isp)) { + /* + * Check to make sure we got a valid loopid + * The 24XX seems to mess this up for multiple channels. + */ + if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT) { + uint8_t alpa = fcp->isp_portid; + + if (alpa == 0) { + /* "Cannot Happen" */ + isp_prt(isp, ISP_LOGWARN, "Zero AL_PA for Loop Topology?"); + } else { + int i; + for (i = 0; alpa_map[i]; i++) { + if (alpa_map[i] == alpa) { + break; + } + } + if (alpa_map[i] && fcp->isp_loopid != i) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d deriving loopid %d from AL_PA map (AL_PA 0x%x) and ignoring returned value %d (AL_PA 0x%x)", chan, i, alpa_map[i], fcp->isp_loopid, alpa); + fcp->isp_loopid = i; + } + } + } + + + if (IS_24XX(isp)) { /* XXX SHOULDN'T THIS BE FOR 2K F/W? XXX */ loopid = NPH_FL_ID; } else { loopid = FL_ID; } - - if (check_for_fabric && isp_getpdb(isp, loopid, &pdb, 1) == 0) { - int r; + if (check_for_fabric) { + r = isp_getpdb(isp, chan, loopid, &pdb, 1); + if (r && (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT)) { + isp_prt(isp, ISP_LOGWARN, "fabric topology but cannot get info about fabric controller (0x%x)", r); + fcp->isp_topo = TOPO_PTP_STUB; + } + } else { + r = -1; + } + if (r == 0) { if (IS_2100(isp)) { fcp->isp_topo = TOPO_FL_PORT; } @@ -2622,13 +2675,30 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) lp->new_portid = lp->portid; lp->new_roles = lp->roles; if (IS_24XX(isp)) { - r = isp_register_fc4_type_24xx(isp); + fcp->inorder = (mbs.param[7] & ISP24XX_INORDER) != 0; + if (ISP_FW_NEWER_THAN(isp, 4, 0, 27)) { + fcp->npiv_fabric = (mbs.param[7] & ISP24XX_NPIV_SAN) != 0; + if (fcp->npiv_fabric) { + isp_prt(isp, ISP_LOGCONFIG, "fabric supports NP-IV"); + } + } + if (chan) { + fcp->isp_sns_hdl = NPH_SNS_HDLBASE + chan; + r = isp_plogx(isp, chan, fcp->isp_sns_hdl, SNS_PORT_ID, PLOGX_FLG_CMD_PLOGI | PLOGX_FLG_COND_PLOGI | PLOGX_FLG_SKIP_PRLI, 0); + if (r) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d cannot log into SNS", __func__, chan); + return (-1); + } + } else { + fcp->isp_sns_hdl = NPH_SNS_ID; + } + r = isp_register_fc4_type_24xx(isp, chan); } else { - r = isp_register_fc4_type(isp); + fcp->isp_sns_hdl = SNS_ID; + r = isp_register_fc4_type(isp, chan); } if (r) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fclink_test: register fc4 type failed"); + isp_prt(isp, ISP_LOGWARN|ISP_LOGSANCFG, "%s: register fc4 type failed", __func__); return (-1); } } else { @@ -2638,20 +2708,23 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) fcp->isp_gbspeed = 1; if (IS_23XX(isp) || IS_24XX(isp)) { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_SET_DATA_RATE; + MBSINIT(&mbs, MBOX_GET_SET_DATA_RATE, MBLOGALL, 3000000); mbs.param[1] = MBGSD_GET_RATE; /* mbs.param[2] undefined if we're just getting rate */ - mbs.logval = MBLOGALL; - mbs.timeout = 3000000; isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - if (mbs.param[1] == MBGSD_FOURGB) { - isp_prt(isp, ISP_LOGINFO, "4Gb link speed/s"); + if (mbs.param[1] == MBGSD_EIGHTGB) { + isp_prt(isp, ISP_LOGINFO, "Chan %d 8Gb link speed", chan); + fcp->isp_gbspeed = 8; + } else if (mbs.param[1] == MBGSD_FOURGB) { + isp_prt(isp, ISP_LOGINFO, "Chan %d 4Gb link speed", chan); fcp->isp_gbspeed = 4; - } if (mbs.param[1] == MBGSD_TWOGB) { - isp_prt(isp, ISP_LOGINFO, "2Gb link speed/s"); + } else if (mbs.param[1] == MBGSD_TWOGB) { + isp_prt(isp, ISP_LOGINFO, "Chan %d 2Gb link speed", chan); fcp->isp_gbspeed = 2; + } else if (mbs.param[1] == MBGSD_ONEGB) { + isp_prt(isp, ISP_LOGINFO, "Chan %d 1Gb link speed", chan); + fcp->isp_gbspeed = 1; } } } @@ -2659,33 +2732,11 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) /* * Announce ourselves, too. */ - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, topology, fcp->isp_portid, - fcp->isp_loopid, toponames[fcp->isp_topo]); - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, ourwwn, - (uint32_t) (ISP_NODEWWN(isp) >> 32), - (uint32_t) ISP_NODEWWN(isp), - (uint32_t) (ISP_PORTWWN(isp) >> 32), - (uint32_t) ISP_PORTWWN(isp)); - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Complete"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, topology, chan, (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) fcp->isp_wwpn, fcp->isp_portid, fcp->isp_loopid, isp_fc_toponame(fcp)); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d FC Link Test Complete", chan); return (0); } -static const char * -ispfc_fw_statename(int state) -{ - switch(state) { - case FW_CONFIG_WAIT: return "Config Wait"; - case FW_WAIT_AL_PA: return "Waiting for AL_PA"; - case FW_WAIT_LOGIN: return "Wait Login"; - case FW_READY: return "Ready"; - case FW_LOSS_OF_SYNC: return "Loss Of Sync"; - case FW_ERROR: return "Error"; - case FW_REINIT: return "Re-Init"; - case FW_NON_PART: return "Nonparticipating"; - default: return "?????"; - } -} - /* * Complete the synchronization of our Port Database. * @@ -2707,9 +2758,9 @@ ispfc_fw_statename(int state) * entities. */ static int -isp_pdb_sync(ispsoftc_t *isp) +isp_pdb_sync(ispsoftc_t *isp, int chan) { - fcparam *fcp = isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); fcportdb_t *lp; uint16_t dbidx; @@ -2732,7 +2783,7 @@ isp_pdb_sync(ispsoftc_t *isp) fcp->isp_topo == TOPO_NL_PORT || fcp->isp_topo == TOPO_N_PORT) { if (fcp->isp_loopstate < LOOP_LSCAN_DONE) { - if (isp_scan_loop(isp) != 0) { + if (isp_scan_loop(isp, chan) != 0) { isp_prt(isp, ISP_LOGWARN, "isp_pdb_sync: isp_scan_loop failed"); return (-1); @@ -2742,7 +2793,7 @@ isp_pdb_sync(ispsoftc_t *isp) if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) { if (fcp->isp_loopstate < LOOP_FSCAN_DONE) { - if (isp_scan_fabric(isp) != 0) { + if (isp_scan_fabric(isp, chan) != 0) { isp_prt(isp, ISP_LOGWARN, "isp_pdb_sync: isp_scan_fabric failed"); return (-1); @@ -2750,14 +2801,15 @@ isp_pdb_sync(ispsoftc_t *isp) } } - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Synchronizing PDBs"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Synchronizing PDBs", chan); fcp->isp_loopstate = LOOP_SYNCING_PDB; for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &fcp->portdb[dbidx]; - if (lp->state == FC_PORTDB_STATE_NIL) { + if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode) { continue; } @@ -2774,12 +2826,13 @@ isp_pdb_sync(ispsoftc_t *isp) case FC_PORTDB_STATE_PROBATIONAL: case FC_PORTDB_STATE_DEAD: /* - * It's up to the outer layers to clear isp_ini_map. + * It's up to the outer layers to clear isp_dev_map. */ lp->state = FC_PORTDB_STATE_NIL; - isp_async(isp, ISPASYNC_DEV_GONE, lp); + isp_async(isp, ISPASYNC_DEV_GONE, chan, lp); if (lp->autologin == 0) { - (void) isp_plogx(isp, lp->handle, lp->portid, + (void) isp_plogx(isp, chan, lp->handle, + lp->portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 0); @@ -2796,12 +2849,12 @@ isp_pdb_sync(ispsoftc_t *isp) case FC_PORTDB_STATE_NEW: /* * It's up to the outer layers to assign a virtual - * target id in isp_ini_map (if any). + * target id in isp_dev_map (if any). */ lp->portid = lp->new_portid; lp->roles = lp->new_roles; lp->state = FC_PORTDB_STATE_VALID; - isp_async(isp, ISPASYNC_DEV_ARRIVED, lp); + isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp); lp->new_roles = 0; lp->new_portid = 0; lp->reserved = 0; @@ -2812,7 +2865,7 @@ isp_pdb_sync(ispsoftc_t *isp) * XXXX FIX THIS */ lp->state = FC_PORTDB_STATE_VALID; - isp_async(isp, ISPASYNC_DEV_CHANGED, lp); + isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp); lp->new_roles = 0; lp->new_portid = 0; lp->reserved = 0; @@ -2821,12 +2874,12 @@ isp_pdb_sync(ispsoftc_t *isp) case FC_PORTDB_STATE_PENDING_VALID: lp->portid = lp->new_portid; lp->roles = lp->new_roles; - if (lp->ini_map_idx) { - int t = lp->ini_map_idx - 1; - fcp->isp_ini_map[t] = dbidx + 1; + if (lp->dev_map_idx) { + int t = lp->dev_map_idx - 1; + fcp->isp_dev_map[t] = dbidx + 1; } lp->state = FC_PORTDB_STATE_VALID; - isp_async(isp, ISPASYNC_DEV_STAYED, lp); + isp_async(isp, ISPASYNC_DEV_STAYED, chan, lp); if (dbidx != FL_ID) { lp->new_roles = 0; lp->new_portid = 0; @@ -2840,7 +2893,7 @@ isp_pdb_sync(ispsoftc_t *isp) isp_prt(isp, ISP_LOGWARN, "isp_scan_loop: state %d for idx %d", lp->state, dbidx); - isp_dump_portdb(isp); + isp_dump_portdb(isp, chan); } } @@ -2858,10 +2911,10 @@ isp_pdb_sync(ispsoftc_t *isp) * Scan local loop for devices. */ static int -isp_scan_loop(ispsoftc_t *isp) +isp_scan_loop(ispsoftc_t *isp, int chan) { fcportdb_t *lp, tmp; - fcparam *fcp = isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); int i; isp_pdb_t pdb; uint16_t handle, lim = 0; @@ -2879,53 +2932,68 @@ isp_scan_loop(ispsoftc_t *isp) * Check our connection topology. * * If we're a public or private loop, we scan 0..125 as handle values. - * The firmware has (typically) peformed a PLOGI for us. + * The firmware has (typically) peformed a PLOGI for us. We skip this + * step if we're a ISP_24XX in NP-IV mode. * * If we're a N-port connection, we treat this is a short loop (0..1). - * - * If we're in target mode, we can all possible handles to see who - * might have logged into us. */ switch (fcp->isp_topo) { case TOPO_NL_PORT: + lim = LOCAL_LOOP_LIM; + break; case TOPO_FL_PORT: + if (IS_24XX(isp) && isp->isp_nchan > 1) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Skipping Local Loop Scan", chan); + fcp->isp_loopstate = LOOP_LSCAN_DONE; + return (0); + } lim = LOCAL_LOOP_LIM; break; case TOPO_N_PORT: lim = 2; break; default: - isp_prt(isp, ISP_LOGDEBUG0, "no loop topology to scan"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d no loop topology to scan", chan); fcp->isp_loopstate = LOOP_LSCAN_DONE; return (0); } fcp->isp_loopstate = LOOP_SCANNING_LOOP; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC scan loop 0..%d", lim-1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop 0..%d", chan, lim-1); /* * Run through the list and get the port database info for each one. */ for (handle = 0; handle < lim; handle++) { + int r; /* - * But don't even try for ourselves... - */ - if (handle == fcp->isp_loopid) { + * Don't scan "special" ids. + */ + if (handle >= FL_ID && handle <= SNS_ID) { continue; } - + if (ISP_CAP_2KLOGIN(isp)) { + if (handle >= NPH_RESERVED && handle <= NPH_FL_ID) { + continue; + } + } /* * In older cards with older f/w GET_PORT_DATABASE has been * known to hang. This trick gets around that problem. */ if (IS_2100(isp) || IS_2200(isp)) { - uint64_t node_wwn = isp_get_portname(isp, handle, 1); + uint64_t node_wwn = isp_get_wwn(isp, chan, handle, 1); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE (bad)", chan); return (-1); } - if (node_wwn == 0) { + if (node_wwn == INI_NONE) { continue; } } @@ -2933,16 +3001,24 @@ isp_scan_loop(ispsoftc_t *isp) /* * Get the port database entity for this index. */ - if (isp_getpdb(isp, handle, &pdb, 1) != 0) { + r = isp_getpdb(isp, chan, handle, &pdb, 1); + if (r != 0) { + isp_prt(isp, ISP_LOGDEBUG1, + "Chan %d FC scan loop handle %d returned %x", + chan, handle, r); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { - ISP_MARK_PORTDB(isp, 1); + ISP_MARK_PORTDB(isp, chan, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE (bad)", chan); return (-1); } continue; } if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { - ISP_MARK_PORTDB(isp, 1); + ISP_MARK_PORTDB(isp, chan, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE (bad)", chan); return (-1); } @@ -2954,8 +3030,10 @@ isp_scan_loop(ispsoftc_t *isp) */ if (IS_2100(isp) && pdb.handle != handle) { isp_prt(isp, ISP_LOGWARN, - "giving up on synchronizing the port database"); - ISP_MARK_PORTDB(isp, 1); + "Chan %d cannot synchronize port database", chan); + ISP_MARK_PORTDB(isp, chan, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE (bad)", chan); return (-1); } @@ -2978,12 +3056,23 @@ isp_scan_loop(ispsoftc_t *isp) a = (tmp.node_wwn == 0); b = (tmp.port_wwn == 0); c = (tmp.portid == 0); + if (a == 0 && b == 0) { + tmp.node_wwn = + isp_get_wwn(isp, chan, handle, 1); + tmp.port_wwn = + isp_get_wwn(isp, chan, handle, 0); + if (tmp.node_wwn && tmp.port_wwn) { + isp_prt(isp, ISP_LOGINFO, "DODGED!"); + goto cont; + } + } isp_prt(isp, ISP_LOGWARN, - "bad pdb (%1d%1d%1d) @ handle 0x%x", a, b, c, - handle); - isp_dump_portdb(isp); + "Chan %d bad pdb (%1d%1d%1d) @ handle 0x%x", chan, + a, b, c, handle); + isp_dump_portdb(isp, chan); continue; } + cont: /* * Now search the entire port database @@ -2991,7 +3080,9 @@ isp_scan_loop(ispsoftc_t *isp) */ for (i = 0; i < MAX_FC_TARG; i++) { lp = &fcp->portdb[i]; - if (lp->state == FC_PORTDB_STATE_NIL) { + + if (lp->state == FC_PORTDB_STATE_NIL || + lp->target_mode) { continue; } if (lp->node_wwn != tmp.node_wwn) { @@ -3008,10 +3099,12 @@ isp_scan_loop(ispsoftc_t *isp) if (lp->state != FC_PORTDB_STATE_PROBATIONAL && lp->state != FC_PORTDB_STATE_ZOMBIE) { isp_prt(isp, ISP_LOGERR, - "[%d] not probational/zombie (0x%x)", - i, lp->state); - isp_dump_portdb(isp); - ISP_MARK_PORTDB(isp, 1); + "Chan %d [%d] not probational/zombie (0x%x)", + chan, i, lp->state); + isp_dump_portdb(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE (bad)", chan); return (-1); } @@ -3031,12 +3124,12 @@ isp_scan_loop(ispsoftc_t *isp) lp->new_portid = tmp.portid; lp->new_roles = tmp.roles; lp->state = FC_PORTDB_STATE_PENDING_VALID; - isp_prt(isp, ISP_LOGSANCFG, - "Loop Port 0x%02x@0x%x Pending Valid", - tmp.portid, tmp.handle); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Loop Port 0x%06x@0x%04x Pending " + "Valid", chan, tmp.portid, tmp.handle); break; } - + /* * We can wipe out the old handle value * here because it's no longer valid. @@ -3047,9 +3140,9 @@ isp_scan_loop(ispsoftc_t *isp) * Claim that this has changed and let somebody else * decide what to do. */ - isp_prt(isp, ISP_LOGSANCFG, - "Loop Port 0x%02x@0x%x changed", - tmp.portid, tmp.handle); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Loop Port 0x%06x@0x%04x changed", + chan, tmp.portid, tmp.handle); lp->state = FC_PORTDB_STATE_CHANGED; lp->new_portid = tmp.portid; lp->new_roles = tmp.roles; @@ -3068,17 +3161,21 @@ isp_scan_loop(ispsoftc_t *isp) * for it and save info for later disposition. */ for (i = 0; i < MAX_FC_TARG; i++) { + if (fcp->portdb[i].target_mode) { + continue; + } if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { break; } } if (i == MAX_FC_TARG) { - isp_prt(isp, ISP_LOGERR, "out of portdb entries"); + isp_prt(isp, ISP_LOGERR, + "Chan %d out of portdb entries", chan); continue; } lp = &fcp->portdb[i]; - MEMZERO(lp, sizeof (fcportdb_t)); + ISP_MEMZERO(lp, sizeof (fcportdb_t)); lp->autologin = 1; lp->state = FC_PORTDB_STATE_NEW; lp->new_portid = tmp.portid; @@ -3086,11 +3183,13 @@ isp_scan_loop(ispsoftc_t *isp) lp->handle = tmp.handle; lp->port_wwn = tmp.port_wwn; lp->node_wwn = tmp.node_wwn; - isp_prt(isp, ISP_LOGSANCFG, - "Loop Port 0x%02x@0x%x is New Entry", - tmp.portid, tmp.handle); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d Loop Port 0x%06x@0x%04x is New Entry", + chan, tmp.portid, tmp.handle); } fcp->isp_loopstate = LOOP_LSCAN_DONE; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC scan loop DONE", chan); return (0); } @@ -3111,31 +3210,32 @@ isp_scan_loop(ispsoftc_t *isp) */ /* - * Take less than half of our scratch area to store Port IDs + * Take less than half of our scratch area to store Port IDs */ -#define GIDLEN ((ISP2100_SCRLEN >> 1) - 16 - SNS_GID_FT_REQ_SIZE) +#define GIDLEN ((ISP_FC_SCRLEN >> 1) - 16 - SNS_GID_FT_REQ_SIZE) #define NGENT ((GIDLEN - 16) >> 2) #define IGPOFF (2 * QENTRY_LEN) -#define OGPOFF (ISP2100_SCRLEN >> 1) -#define ZTXOFF (ISP2100_SCRLEN - (1 * QENTRY_LEN)) -#define CTXOFF (ISP2100_SCRLEN - (2 * QENTRY_LEN)) -#define XTXOFF (ISP2100_SCRLEN - (3 * QENTRY_LEN)) +#define OGPOFF (ISP_FC_SCRLEN >> 1) +#define ZTXOFF (ISP_FC_SCRLEN - (1 * QENTRY_LEN)) +#define CTXOFF (ISP_FC_SCRLEN - (2 * QENTRY_LEN)) +#define XTXOFF (ISP_FC_SCRLEN - (3 * QENTRY_LEN)) static int -isp_gid_ft_sns(ispsoftc_t *isp) +isp_gid_ft_sns(ispsoftc_t *isp, int chan) { union { sns_gid_ft_req_t _x; uint8_t _y[SNS_GID_FT_REQ_SIZE]; } un; - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, chan); sns_gid_ft_req_t *rq = &un._x; mbreg_t mbs; - isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT) via SNS"); + isp_prt(isp, ISP_LOGDEBUG0, + "Chan %d scanning fabric (GID_FT) via SNS", chan); - MEMZERO(rq, SNS_GID_FT_REQ_SIZE); + ISP_MEMZERO(rq, SNS_GID_FT_REQ_SIZE); rq->snscb_rblen = GIDLEN >> 1; rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + IGPOFF); rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + IGPOFF); @@ -3149,15 +3249,13 @@ isp_gid_ft_sns(ispsoftc_t *isp) isp_put_gid_ft_request(isp, rq, fcp->isp_scratch); MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE); - MEMZERO(&mbs, sizeof (mbs)); + MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 10000000); mbs.param[0] = MBOX_SEND_SNS; mbs.param[1] = SNS_GID_FT_REQ_SIZE >> 1; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - mbs.logval = MBLOGALL; - mbs.timeout = 10000000; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { if (mbs.param[0] == MBOX_INVALID_COMMAND) { @@ -3170,10 +3268,10 @@ isp_gid_ft_sns(ispsoftc_t *isp) } static int -isp_gid_ft_ct_passthru(ispsoftc_t *isp) +isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) { mbreg_t mbs; - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, chan); union { isp_ct_pt_t plocal; ct_hdr_t clocal; @@ -3184,7 +3282,8 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) uint32_t *rp; uint8_t *scp = fcp->isp_scratch; - isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT) via CT"); + isp_prt(isp, ISP_LOGDEBUG0, + "Chan %d scanning fabric (GID_FT) via CT", chan); if (!IS_24XX(isp)) { return (1); @@ -3194,12 +3293,13 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) * Build a Passthrough IOCB in memory. */ pt = &un.plocal; - MEMZERO(un.q, QENTRY_LEN); + ISP_MEMZERO(un.q, QENTRY_LEN); pt->ctp_header.rqs_entry_count = 1; pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; pt->ctp_handle = 0xffffffff; - pt->ctp_nphdl = NPH_SNS_ID; + pt->ctp_nphdl = fcp->isp_sns_hdl; pt->ctp_cmd_cnt = 1; + pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); pt->ctp_time = 30; pt->ctp_rsp_cnt = 1; pt->ctp_rsp_bcnt = GIDLEN; @@ -3221,7 +3321,7 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) * Note that the CT header has to end up as Big Endian format in memory. */ ct = &un.clocal; - MEMZERO(ct, sizeof (*ct)); + ISP_MEMZERO(ct, sizeof (*ct)); ct->ct_revision = CT_REVISION; ct->ct_fcs_type = CT_FC_TYPE_FC; ct->ct_fcs_subtype = CT_FC_SUBTYPE_NS; @@ -3235,16 +3335,13 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) isp_print_bytes(isp, "CT HDR + payload after put", sizeof (*ct) + sizeof (uint32_t), &scp[XTXOFF]); } - MEMZERO(&scp[ZTXOFF], QENTRY_LEN); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + ISP_MEMZERO(&scp[ZTXOFF], QENTRY_LEN); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); - mbs.timeout = 500000; - mbs.logval = MBLOGALL; MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { @@ -3258,8 +3355,9 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) } if (pt->ctp_status && pt->ctp_status != RQCS_DATA_UNDERRUN) { - isp_prt(isp, ISP_LOGWARN, "CT Passthrough returned 0x%x", - pt->ctp_status); + isp_prt(isp, ISP_LOGWARN, + "Chan %d ISP GID FT CT Passthrough returned 0x%x", + chan, pt->ctp_status); return (-1); } MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN + 16); @@ -3270,15 +3368,17 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp) } static int -isp_scan_fabric(ispsoftc_t *isp) +isp_scan_fabric(ispsoftc_t *isp, int chan) { - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, chan); uint32_t portid; - uint16_t handle, oldhandle; + uint16_t handle, oldhandle, loopid; + isp_pdb_t pdb; int portidx, portlim, r; sns_gid_ft_rsp_t *rs0, *rs1; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC Scan Fabric", chan); if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate < LOOP_LSCAN_DONE) { return (-1); @@ -3289,37 +3389,72 @@ isp_scan_fabric(ispsoftc_t *isp) if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) { fcp->isp_loopstate = LOOP_FSCAN_DONE; isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "FC Scan Fabric Done (no fabric)"); + "Chan %d FC Scan Fabric Done (no fabric)", chan); return (0); } - FC_SCRATCH_ACQUIRE(isp); fcp->isp_loopstate = LOOP_SCANNING_FABRIC; + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } + + /* + * Make sure we still are logged into the fabric controller. + */ + if (IS_24XX(isp)) { /* XXX SHOULDN'T THIS BE TRUE FOR 2K F/W? XXX */ + loopid = NPH_FL_ID; + } else { + loopid = FL_ID; + } + r = isp_getpdb(isp, chan, loopid, &pdb, 0); + if (r == MBOX_NOT_LOGGED_IN) { + isp_dump_chip_portdb(isp, chan, 0); + } + if (r) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } if (IS_24XX(isp)) { - r = isp_gid_ft_ct_passthru(isp); + r = isp_gid_ft_ct_passthru(isp, chan); } else { - r = isp_gid_ft_sns(isp); + r = isp_gid_ft_sns(isp, chan); + } + + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); } if (r > 0) { fcp->isp_loopstate = LOOP_FSCAN_DONE; - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); return (0); } else if (r < 0) { fcp->isp_loopstate = LOOP_PDB_RCVD; /* try again */ - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); return (0); } - if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - FC_SCRATCH_RELEASE(isp); - return (-1); - } MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN); rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF); rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF); isp_get_gid_ft_response(isp, rs0, rs1, NGENT); + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) { int level; if (rs1->snscb_cthdr.ct_reason == 9 && @@ -3328,10 +3463,11 @@ isp_scan_fabric(ispsoftc_t *isp) } else { level = ISP_LOGWARN; } - isp_prt(isp, level, "Fabric Nameserver rejected GID_FT " - "(Reason=0x%x Expl=0x%x)", rs1->snscb_cthdr.ct_reason, + isp_prt(isp, level, "Chan %d Fabric Nameserver rejected GID_FT" + " (Reason=0x%x Expl=0x%x)", chan, + rs1->snscb_cthdr.ct_reason, rs1->snscb_cthdr.ct_explanation); - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } @@ -3345,12 +3481,10 @@ isp_scan_fabric(ispsoftc_t *isp) /* * Prime the handle we will start using. */ - oldhandle = NIL_HANDLE; + oldhandle = FCPARAM(isp, 0)->isp_lasthdl; /* - * Okay, we now have a list of Port IDs for all FC4 SCSI devices - * that the Fabric Name server knows about. Go through the list - * and remove duplicate port ids. + * Go through the list and remove duplicate port ids. */ portlim = 0; @@ -3366,11 +3500,11 @@ isp_scan_fabric(ispsoftc_t *isp) */ if ((rs1->snscb_ports[portidx].control & 0x80) == 0) { isp_prt(isp, ISP_LOGWARN, - "fabric too big for scratch area: increase ISP2100_SCRLEN"); + "fabric too big for scratch area: increase ISP_FC_SCRLEN"); } portlim = portidx + 1; isp_prt(isp, ISP_LOGSANCFG, - "got %d ports back from name server", portlim); + "Chan %d got %d ports back from name server", chan, portlim); for (portidx = 0; portidx < portlim; portidx++) { int npidx; @@ -3395,18 +3529,18 @@ isp_scan_fabric(ispsoftc_t *isp) rs1->snscb_ports[npidx].portid[1] = 0; rs1->snscb_ports[npidx].portid[2] = 0; isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "removing duplicate PortID 0x%x entry from list", - portid); + "Chan %d removing duplicate PortID 0x%06x" + " entry from list", chan, portid); } } /* - * Okay, we now have a list of Port IDs for all FC4 SCSI devices + * We now have a list of Port IDs for all FC4 SCSI devices * that the Fabric Name server knows about. * * For each entry on this list go through our port database looking * for probational entries- if we find one, then an old entry is - * is maybe still this one. We get some information to find out. + * maybe still this one. We get some information to find out. * * Otherwise, it's a new fabric device, and we log into it * (unconditionally). After searching the entire database @@ -3417,7 +3551,6 @@ isp_scan_fabric(ispsoftc_t *isp) for (portidx = 0; portidx < portlim; portidx++) { fcportdb_t *lp; - isp_pdb_t pdb; uint64_t wwnn, wwpn; int dbidx, nr; @@ -3428,20 +3561,35 @@ isp_scan_fabric(ispsoftc_t *isp) if (portid == 0) { isp_prt(isp, ISP_LOGSANCFG, - "skipping null PortID at idx %d", portidx); + "Chan %d skipping null PortID at idx %d", + chan, portidx); continue; } /* - * Skip ourselves... + * Skip ourselves here and on other channels. If we're + * multi-id, we can't check the portids in other FCPARAM + * arenas because the resolutions here aren't synchronized. + * The best way to do this is to exclude looking at portids + * that have the same domain and area code as our own + * portid. */ - if (portid == fcp->isp_portid) { + if (ISP_CAP_MULTI_ID(isp)) { + if ((portid >> 8) == (fcp->isp_portid >> 8)) { + isp_prt(isp, ISP_LOGSANCFG, + "Chan %d skip PortID 0x%06x", + chan, portid); + continue; + } + } else if (portid == fcp->isp_portid) { isp_prt(isp, ISP_LOGSANCFG, - "skip ourselves @ PortID 0x%06x", portid); + "Chan %d skip ourselves on @ PortID 0x%06x", + chan, portid); continue; } + isp_prt(isp, ISP_LOGSANCFG, - "Checking Fabric Port 0x%06x", portid); + "Chan %d Checking Fabric Port 0x%06x", chan, portid); /* * We now search our Port Database for any @@ -3452,7 +3600,8 @@ isp_scan_fabric(ispsoftc_t *isp) for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &fcp->portdb[dbidx]; - if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { + if (lp->state != FC_PORTDB_STATE_PROBATIONAL || + lp->target_mode) { continue; } if (lp->portid == portid) { @@ -3485,18 +3634,18 @@ isp_scan_fabric(ispsoftc_t *isp) * */ - r = isp_getpdb(isp, lp->handle, &pdb, 0); + r = isp_getpdb(isp, chan, lp->handle, &pdb, 0); if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - FC_SCRATCH_RELEASE(isp); - ISP_MARK_PORTDB(isp, 1); + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); return (-1); } if (r != 0) { lp->new_portid = portid; lp->state = FC_PORTDB_STATE_DEAD; isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Fabric Port 0x%06x considered dead", - portid); + "Chan %d Fabric Port 0x%06x is dead", + chan, portid); continue; } @@ -3514,7 +3663,7 @@ isp_scan_fabric(ispsoftc_t *isp) wwpn != lp->port_wwn || wwnn != lp->node_wwn) { isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - fconf, dbidx, pdb.handle, pdb.portid, + fconf, chan, dbidx, pdb.handle, pdb.portid, (uint32_t) (wwnn >> 32), (uint32_t) wwnn, (uint32_t) (wwpn >> 32), (uint32_t) wwpn, lp->handle, portid, @@ -3525,23 +3674,30 @@ isp_scan_fabric(ispsoftc_t *isp) /* * Try to re-login to this device using a * new handle. If that fails, mark it dead. - * + * * isp_login_device will check for handle and * portid consistency after re-login. - * + * */ - if (isp_login_device(isp, portid, &pdb, + if (isp_login_device(isp, chan, portid, &pdb, &oldhandle)) { lp->new_portid = portid; lp->state = FC_PORTDB_STATE_DEAD; if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - FC_SCRATCH_RELEASE(isp); - ISP_MARK_PORTDB(isp, 1); + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); return (-1); } continue; } + if (fcp->isp_loopstate != + LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } + FCPARAM(isp, 0)->isp_lasthdl = oldhandle; MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); if (wwpn != lp->port_wwn || @@ -3576,12 +3732,13 @@ isp_scan_fabric(ispsoftc_t *isp) if (pdb.portid != lp->portid || nr != lp->roles || handle_changed) { isp_prt(isp, ISP_LOGSANCFG, - "Fabric Port 0x%06x changed", portid); + "Chan %d Fabric Port 0x%06x changed", + chan, portid); lp->state = FC_PORTDB_STATE_CHANGED; } else { isp_prt(isp, ISP_LOGSANCFG, - "Fabric Port 0x%06x Now Pending Valid", - portid); + "Chan %d Fabric Port 0x%06x " + "Now Pending Valid", chan, portid); lp->state = FC_PORTDB_STATE_PENDING_VALID; } continue; @@ -3593,13 +3750,19 @@ isp_scan_fabric(ispsoftc_t *isp) * with the same port id. While we're at it, mark where the * last free entry was. */ - + dbidx = MAX_FC_TARG; for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { if (lp >= &fcp->portdb[FL_ID] && lp <= &fcp->portdb[SNS_ID]) { continue; } + /* + * Skip any target mode entries. + */ + if (lp->target_mode) { + continue; + } if (lp->state == FC_PORTDB_STATE_NIL) { if (dbidx == MAX_FC_TARG) { dbidx = lp - fcp->portdb; @@ -3615,9 +3778,9 @@ isp_scan_fabric(ispsoftc_t *isp) } if (lp < &fcp->portdb[MAX_FC_TARG]) { - isp_prt(isp, ISP_LOGWARN, - "PortID 0x%06x already at %d handle %d state %d", - portid, dbidx, lp->handle, lp->state); + isp_prt(isp, ISP_LOGWARN, "Chan %d PortID 0x%06x " + "already at %d handle %d state %d", + chan, portid, dbidx, lp->handle, lp->state); continue; } @@ -3643,14 +3806,20 @@ isp_scan_fabric(ispsoftc_t *isp) * isp_login_device will check for handle and * portid consistency after login. */ - if (isp_login_device(isp, portid, &pdb, &oldhandle)) { + if (isp_login_device(isp, chan, portid, &pdb, &oldhandle)) { if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - FC_SCRATCH_RELEASE(isp); - ISP_MARK_PORTDB(isp, 1); + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); return (-1); } continue; } + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp, chan); + ISP_MARK_PORTDB(isp, chan, 1); + return (-1); + } + FCPARAM(isp, 0)->isp_lasthdl = oldhandle; handle = pdb.handle; MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); @@ -3666,7 +3835,7 @@ isp_scan_fabric(ispsoftc_t *isp) if (dbidx >= FL_ID && dbidx <= SNS_ID) { continue; } - if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { + if (fcp->portdb[dbidx].target_mode) { continue; } if (fcp->portdb[dbidx].node_wwn == wwnn && @@ -3676,7 +3845,7 @@ isp_scan_fabric(ispsoftc_t *isp) } if (dbidx == MAX_FC_TARG) { - MEMZERO(lp, sizeof (fcportdb_t)); + ISP_MEMZERO(lp, sizeof (fcportdb_t)); lp->handle = handle; lp->node_wwn = wwnn; lp->port_wwn = wwpn; @@ -3684,14 +3853,15 @@ isp_scan_fabric(ispsoftc_t *isp) lp->new_roles = nr; lp->state = FC_PORTDB_STATE_NEW; isp_prt(isp, ISP_LOGSANCFG, - "Fabric Port 0x%06x is New Entry", portid); + "Chan %d Fabric Port 0x%06x is a New Entry", + chan, portid); continue; } if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) { isp_prt(isp, ISP_LOGWARN, - "PortID 0x%x 0x%08x%08x/0x%08x%08x %ld already at " - "idx %d, state 0x%x", portid, + "Chan %d PortID 0x%x 0x%08x%08x/0x%08x%08x %ld " + "already at idx %d, state 0x%x", chan, portid, (uint32_t) (wwnn >> 32), (uint32_t) wwnn, (uint32_t) (wwpn >> 32), (uint32_t) wwpn, (long) (lp - fcp->portdb), dbidx, @@ -3713,23 +3883,25 @@ isp_scan_fabric(ispsoftc_t *isp) lp->new_roles = nr; if (lp->portid != portid || lp->roles != nr) { isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Zombie Fabric Port 0x%06x Now Changed", portid); + "Chan %d Zombie Fabric Port 0x%06x Now Changed", + chan, portid); lp->state = FC_PORTDB_STATE_CHANGED; } else { isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Zombie Fabric Port 0x%06x Now Pending Valid", - portid); + "Chan %d Zombie Fabric Port 0x%06x " + "Now Pending Valid", chan, portid); lp->state = FC_PORTDB_STATE_PENDING_VALID; } } - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - ISP_MARK_PORTDB(isp, 1); + ISP_MARK_PORTDB(isp, chan, 1); return (-1); } fcp->isp_loopstate = LOOP_FSCAN_DONE; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric Done"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Chan %d FC Scan Fabric Done", chan); return (0); } @@ -3737,39 +3909,41 @@ isp_scan_fabric(ispsoftc_t *isp) * Find an unused handle and try and use to login to a port. */ static int -isp_login_device(ispsoftc_t *isp, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) +isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, + uint16_t *ohp) { int lim, i, r; uint16_t handle; - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { lim = NPH_MAX_2K; } else { lim = NPH_MAX; } - handle = isp_nxt_handle(isp, *ohp); + handle = isp_nxt_handle(isp, chan, *ohp); for (i = 0; i < lim; i++) { /* * See if we're still logged into something with * this handle and that something agrees with this * port id. */ - r = isp_getpdb(isp, handle, p, 0); + r = isp_getpdb(isp, chan, handle, p, 0); if (r == 0 && p->portid != portid) { - (void) isp_plogx(isp, handle, portid, + (void) isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT, 1); } else if (r == 0) { break; } - if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { return (-1); } /* * Now try and log into the device */ - r = isp_plogx(isp, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); - if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + r = isp_plogx(isp, chan, handle, portid, + PLOGX_FLG_CMD_PLOGI, 1); + if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { return (-1); } if (r == 0) { @@ -3781,14 +3955,17 @@ isp_login_device(ispsoftc_t *isp, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) } else if (r != MBOX_LOOP_ID_USED) { i = lim; break; + } else if (r == MBOX_TIMEOUT) { + return (-1); } else { *ohp = handle; - handle = isp_nxt_handle(isp, *ohp); + handle = isp_nxt_handle(isp, chan, *ohp); } } if (i == lim) { - isp_prt(isp, ISP_LOGWARN, "PLOGI 0x%06x failed", portid); + isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed", + chan, portid); return (-1); } @@ -3797,34 +3974,35 @@ isp_login_device(ispsoftc_t *isp, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) * so we can crosscheck that it is still what we think it * is and that we also have the role it plays */ - r = isp_getpdb(isp, handle, p, 0); - if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + r = isp_getpdb(isp, chan, handle, p, 0); + if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { return (-1); } if (r != 0) { - isp_prt(isp, ISP_LOGERR, "new device 0x%06x@0x%x disappeared", - portid, handle); + isp_prt(isp, ISP_LOGERR, + "Chan %d new device 0x%06x@0x%x disappeared", + chan, portid, handle); return (-1); } if (p->handle != handle || p->portid != portid) { isp_prt(isp, ISP_LOGERR, - "new device 0x%06x@0x%x changed (0x%06x@0x%0x)", - portid, handle, p->portid, p->handle); + "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)", + chan, portid, handle, p->portid, p->handle); return (-1); } return (0); } static int -isp_register_fc4_type(ispsoftc_t *isp) +isp_register_fc4_type(ispsoftc_t *isp, int chan) { - fcparam *fcp = isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); uint8_t local[SNS_RFT_ID_REQ_SIZE]; sns_screq_t *reqp = (sns_screq_t *) local; mbreg_t mbs; - MEMZERO((void *) reqp, SNS_RFT_ID_REQ_SIZE); + ISP_MEMZERO((void *) reqp, SNS_RFT_ID_REQ_SIZE); reqp->snscb_rblen = SNS_RFT_ID_RESP_SIZE >> 1; reqp->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + 0x100); reqp->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + 0x100); @@ -3835,20 +4013,20 @@ isp_register_fc4_type(ispsoftc_t *isp) reqp->snscb_data[4] = fcp->isp_portid & 0xffff; reqp->snscb_data[5] = (fcp->isp_portid >> 16) & 0xff; reqp->snscb_data[6] = (1 << FC4_SCSI); - FC_SCRATCH_ACQUIRE(isp); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } isp_put_sns_request(isp, reqp, (sns_screq_t *) fcp->isp_scratch); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SEND_SNS; + MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 1000000); mbs.param[1] = SNS_RFT_ID_REQ_SIZE >> 1; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - mbs.logval = MBLOGALL; - mbs.timeout = 10000000; MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_RFT_ID_REQ_SIZE); isp_mboxcmd(isp, &mbs); - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { return (0); } else { @@ -3857,10 +4035,10 @@ isp_register_fc4_type(ispsoftc_t *isp) } static int -isp_register_fc4_type_24xx(ispsoftc_t *isp) +isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) { mbreg_t mbs; - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, chan); union { isp_ct_pt_t plocal; rft_id_t clocal; @@ -3871,17 +4049,22 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp) rft_id_t *rp; uint8_t *scp = fcp->isp_scratch; - FC_SCRATCH_ACQUIRE(isp); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } + /* * Build a Passthrough IOCB in memory. */ - MEMZERO(un.q, QENTRY_LEN); + ISP_MEMZERO(un.q, QENTRY_LEN); pt = &un.plocal; pt->ctp_header.rqs_entry_count = 1; pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; pt->ctp_handle = 0xffffffff; - pt->ctp_nphdl = NPH_SNS_ID; + pt->ctp_nphdl = fcp->isp_sns_hdl; pt->ctp_cmd_cnt = 1; + pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); pt->ctp_time = 1; pt->ctp_rsp_cnt = 1; pt->ctp_rsp_bcnt = sizeof (ct_hdr_t); @@ -3893,13 +4076,16 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp) pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t); isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "IOCB CT Request", QENTRY_LEN, pt); + } /* * Build the CT header and command in memory. * * Note that the CT header has to end up as Big Endian format in memory. */ - MEMZERO(&un.clocal, sizeof (un.clocal)); + ISP_MEMZERO(&un.clocal, sizeof (un.clocal)); ct = &un.clocal.rftid_hdr; ct->ct_revision = CT_REVISION; ct->ct_fcs_type = CT_FC_TYPE_FC; @@ -3912,22 +4098,22 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp) rp->rftid_portid[2] = fcp->isp_portid; rp->rftid_fc4types[FC4_SCSI >> 5] = 1 << (FC4_SCSI & 0x1f); isp_put_rft_id(isp, rp, (rft_id_t *) &scp[XTXOFF]); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "CT Header", QENTRY_LEN, &scp[XTXOFF]); + } - MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); + ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); - mbs.timeout = 500000; - mbs.logval = MBLOGALL; MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); return (-1); } MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN); @@ -3937,36 +4123,38 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp) isp_print_bytes(isp, "IOCB response", QENTRY_LEN, pt); } if (pt->ctp_status) { - FC_SCRATCH_RELEASE(isp); - isp_prt(isp, ISP_LOGWARN, "CT Passthrough returned 0x%x", - pt->ctp_status); - return (-1); + FC_SCRATCH_RELEASE(isp, chan); + isp_prt(isp, ISP_LOGWARN, + "Chan %d Register FC4 Type CT Passthrough returned 0x%x", + chan, pt->ctp_status); + return (1); } isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct); - FC_SCRATCH_RELEASE(isp); + FC_SCRATCH_RELEASE(isp, chan); if (ct->ct_cmd_resp == LS_RJT) { isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Register FC4 Type rejected"); + "Chan %d Register FC4 Type rejected", chan); return (-1); } else if (ct->ct_cmd_resp == LS_ACC) { isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Register FC4 Type accepted"); - return(0); + "Chan %d Register FC4 Type accepted", chan); + return (0); } else { isp_prt(isp, ISP_LOGWARN, - "Register FC4 Type: 0x%x", ct->ct_cmd_resp); + "Chan %d Register FC4 Type: 0x%x", + chan, ct->ct_cmd_resp); return (-1); } } static uint16_t -isp_nxt_handle(ispsoftc_t *isp, uint16_t handle) +isp_nxt_handle(ispsoftc_t *isp, int chan, uint16_t handle) { int i; if (handle == NIL_HANDLE) { - if (FCPARAM(isp)->isp_topo == TOPO_F_PORT) { + if (FCPARAM(isp, chan)->isp_topo == TOPO_F_PORT) { handle = 0; } else { handle = SNS_ID+1; @@ -3979,7 +4167,7 @@ isp_nxt_handle(ispsoftc_t *isp, uint16_t handle) if (handle >= NPH_RESERVED && handle <= NPH_FL_ID) { handle = NPH_FL_ID+1; } - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { if (handle == NPH_MAX_2K) { handle = 0; } @@ -3989,15 +4177,16 @@ isp_nxt_handle(ispsoftc_t *isp, uint16_t handle) } } } - if (handle == FCPARAM(isp)->isp_loopid) { - return (isp_nxt_handle(isp, handle)); + if (handle == FCPARAM(isp, chan)->isp_loopid) { + return (isp_nxt_handle(isp, chan, handle)); } for (i = 0; i < MAX_FC_TARG; i++) { - if (FCPARAM(isp)->portdb[i].state == FC_PORTDB_STATE_NIL) { + if (FCPARAM(isp, chan)->portdb[i].state == + FC_PORTDB_STATE_NIL) { continue; } - if (FCPARAM(isp)->portdb[i].handle == handle) { - return (isp_nxt_handle(isp, handle)); + if (FCPARAM(isp, chan)->portdb[i].handle == handle) { + return (isp_nxt_handle(isp, chan, handle)); } } return (handle); @@ -4011,24 +4200,16 @@ int isp_start(XS_T *xs) { ispsoftc_t *isp; - uint32_t nxti, optr, handle; + uint32_t handle; uint8_t local[QENTRY_LEN]; - ispreq_t *reqp, *qep; - void *cdbp; + ispreq_t *reqp; + void *cdbp, *qep; uint16_t *tptr; - int target, i, hdlidx = 0; + int target, dmaresult, hdlidx = 0; XS_INITERR(xs); isp = XS_ISP(xs); - /* - * Check to make sure we're supporting initiator role. - */ - if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - /* * Now make sure we're running. */ @@ -4047,9 +4228,7 @@ isp_start(XS_T *xs) */ if (XS_CDBLEN(xs) > (IS_FC(isp)? 16 : 44) || XS_CDBLEN(xs) == 0) { - isp_prt(isp, ISP_LOGERR, - "unsupported cdb length (%d, CDB[0]=0x%x)", - XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff); + isp_prt(isp, ISP_LOGERR, "unsupported cdb length (%d, CDB[0]=0x%x)", XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff); XS_SETERR(xs, HBA_BOTCH); return (CMD_COMPLETE); } @@ -4060,13 +4239,17 @@ isp_start(XS_T *xs) */ target = XS_TGT(xs); if (IS_FC(isp)) { - fcparam *fcp = isp->isp_param; + fcparam *fcp = FCPARAM(isp, XS_CHANNEL(xs)); + + if ((fcp->role & ISP_ROLE_INITIATOR) == 0) { + XS_SETERR(xs, HBA_SELTIMEOUT); + return (CMD_COMPLETE); + } /* * Try again later. */ - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_READY) { + if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_READY) { return (CMD_RQLATER); } @@ -4075,9 +4258,8 @@ isp_start(XS_T *xs) return (CMD_COMPLETE); } - hdlidx = fcp->isp_ini_map[XS_TGT(xs)] - 1; - isp_prt(isp, ISP_LOGDEBUG1, "XS_TGT(xs)=%d- hdlidx value %d", - XS_TGT(xs), hdlidx); + hdlidx = fcp->isp_dev_map[XS_TGT(xs)] - 1; + isp_prt(isp, ISP_LOGDEBUG2, "XS_TGT(xs)=%d- hdlidx value %d", XS_TGT(xs), hdlidx); if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); @@ -4090,22 +4272,27 @@ isp_start(XS_T *xs) return (CMD_COMPLETE); } target = fcp->portdb[hdlidx].handle; - } - - /* - * Next check to see if any HBA or Device parameters need to be updated. - */ - if (isp->isp_update != 0) { - isp_update(isp); + fcp->portdb[hdlidx].dirty = 1; + } else { + sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); + if ((sdp->role & ISP_ROLE_INITIATOR) == 0) { + XS_SETERR(xs, HBA_SELTIMEOUT); + return (CMD_COMPLETE); + } + if (sdp->update) { + isp_spi_update(isp, XS_CHANNEL(xs)); + } } start_again: - if (isp_getrqentry(isp, &nxti, &optr, (void *)&qep)) { + qep = isp_getrqentry(isp); + if (qep == NULL) { isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow"); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } + XS_SETERR(xs, HBA_NOERROR); /* * Now see if we need to synchronize the ISP with respect to anything. @@ -4113,47 +4300,38 @@ isp_start(XS_T *xs) * than which we got here to send a command to. */ reqp = (ispreq_t *) local; - if (isp->isp_sendmarker) { + ISP_MEMZERO(local, QENTRY_LEN); + if (ISP_TST_SENDMARKER(isp, XS_CHANNEL(xs))) { if (IS_24XX(isp)) { - isp_marker_24xx_t *m = (isp_marker_24xx_t *) qep; - MEMZERO(m, QENTRY_LEN); + isp_marker_24xx_t *m = (isp_marker_24xx_t *) reqp; m->mrk_header.rqs_entry_count = 1; m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; m->mrk_modifier = SYNC_ALL; - isp_put_marker_24xx(isp, m, (isp_marker_24xx_t *)qep); - ISP_ADD_REQUEST(isp, nxti); - isp->isp_sendmarker = 0; - goto start_again; + isp_put_marker_24xx(isp, m, qep); } else { - for (i = 0; i < (IS_DUALBUS(isp)? 2: 1); i++) { - isp_marker_t *m = (isp_marker_t *) qep; - if ((isp->isp_sendmarker & (1 << i)) == 0) { - continue; - } - MEMZERO(m, QENTRY_LEN); - m->mrk_header.rqs_entry_count = 1; - m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; - m->mrk_target = (i << 7); /* bus # */ - m->mrk_modifier = SYNC_ALL; - isp_put_marker(isp, m, (isp_marker_t *) qep); - ISP_ADD_REQUEST(isp, nxti); - isp->isp_sendmarker &= ~(1 << i); - goto start_again; - } + isp_marker_t *m = (isp_marker_t *) reqp; + m->mrk_header.rqs_entry_count = 1; + m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; + m->mrk_target = (XS_CHANNEL(xs) << 7); /* bus # */ + m->mrk_modifier = SYNC_ALL; + isp_put_marker(isp, m, qep); } + ISP_SYNC_REQUEST(isp); + ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 0); + goto start_again; } - MEMZERO((void *)reqp, QENTRY_LEN); reqp->req_header.rqs_entry_count = 1; if (IS_24XX(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T7RQS; } else if (IS_FC(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; } else { - if (XS_CDBLEN(xs) > 12) + if (XS_CDBLEN(xs) > 12) { reqp->req_header.rqs_entry_type = RQSTYPE_CMDONLY; - else + } else { reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST; + } } /* reqp->req_header.rqs_flags = 0; */ /* reqp->req_header.rqs_seqno = 0; */ @@ -4180,7 +4358,7 @@ isp_start(XS_T *xs) /* * See comment in isp_intr */ - /* XS_RESID(xs) = 0; */ + /* XS_SET_RESID(xs, 0); */ /* * Fibre Channel always requires some kind of tag. @@ -4200,10 +4378,8 @@ isp_start(XS_T *xs) ((ispreqt2_t *)reqp)->req_flags = REQFLAG_STAG; } } else { - sdparam *sdp = (sdparam *)isp->isp_param; - sdp += XS_CHANNEL(xs); - if ((sdp->isp_devparam[target].actv_flags & DPARM_TQING) && - XS_TAG_P(xs)) { + sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); + if ((sdp->isp_devparam[target].actv_flags & DPARM_TQING) && XS_TAG_P(xs)) { reqp->req_flags = XS_TAG_TYPE(xs); } } @@ -4217,10 +4393,11 @@ isp_start(XS_T *xs) } else if (IS_24XX(isp)) { fcportdb_t *lp; - lp = &FCPARAM(isp)->portdb[hdlidx]; + lp = &FCPARAM(isp, XS_CHANNEL(xs))->portdb[hdlidx]; ((ispreqt7_t *)reqp)->req_nphdl = target; ((ispreqt7_t *)reqp)->req_tidlo = lp->portid; ((ispreqt7_t *)reqp)->req_tidhi = lp->portid >> 16; + ((ispreqt7_t *)reqp)->req_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(xs)); if (XS_LUN(xs) > 256) { ((ispreqt7_t *)reqp)->req_lun[0] = XS_LUN(xs) >> 8; ((ispreqt7_t *)reqp)->req_lun[0] |= 0x40; @@ -4228,17 +4405,17 @@ isp_start(XS_T *xs) ((ispreqt7_t *)reqp)->req_lun[1] = XS_LUN(xs); cdbp = ((ispreqt7_t *)reqp)->req_cdb; tptr = &((ispreqt7_t *)reqp)->req_time; - } else if (FCPARAM(isp)->isp_2klogin) { + } else if (ISP_CAP_2KLOGIN(isp)) { ((ispreqt2e_t *)reqp)->req_target = target; ((ispreqt2e_t *)reqp)->req_scclun = XS_LUN(xs); - } else if (FCPARAM(isp)->isp_sccfw) { + } else if (ISP_CAP_SCCFW(isp)) { ((ispreqt2_t *)reqp)->req_target = target; ((ispreqt2_t *)reqp)->req_scclun = XS_LUN(xs); } else { ((ispreqt2_t *)reqp)->req_target = target; ((ispreqt2_t *)reqp)->req_lun_trn = XS_LUN(xs); } - MEMCPY(cdbp, XS_CDBP(xs), XS_CDBLEN(xs)); + ISP_MEMCPY(cdbp, XS_CDBP(xs), XS_CDBLEN(xs)); *tptr = XS_TIME(xs) / 1000; if (*tptr == 0 && XS_TIME(xs)) { @@ -4257,24 +4434,21 @@ isp_start(XS_T *xs) reqp->req_handle = handle; /* - * Set up DMA and/or do any bus swizzling of the request entry + * Set up DMA and/or do any platform dependent swizzling of the request entry * so that the Qlogic F/W understands what is being asked of it. + * + * The callee is responsible for adding all requests at this point. */ - i = ISP_DMASETUP(isp, xs, reqp, &nxti, optr); - if (i != CMD_QUEUED) { + dmaresult = ISP_DMASETUP(isp, xs, reqp); + if (dmaresult != CMD_QUEUED) { isp_destroy_handle(isp, handle); /* * dmasetup sets actual error in packet, and * return what we were given to return. */ - return (i); + return (dmaresult); } - XS_SETERR(xs, HBA_NOERROR); - isp_prt(isp, ISP_LOGDEBUG0, - "START cmd for %d.%d.%d cmd 0x%x datalen %ld", - XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), XS_CDBP(xs)[0], - (long) XS_XFRLEN(xs)); - ISP_ADD_REQUEST(isp, nxti); + isp_prt(isp, ISP_LOGDEBUG0, "START cmd for %d.%d.%d cmd 0x%x datalen %ld", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), XS_CDBP(xs)[0], (long) XS_XFRLEN(xs)); isp->isp_nactive++; return (CMD_QUEUED); } @@ -4285,20 +4459,15 @@ isp_start(XS_T *xs) */ int -isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) +isp_control(ispsoftc_t *isp, ispctl_t ctl, ...) { XS_T *xs; - mbreg_t mbs; - int bus, tgt; + mbreg_t *mbr, mbs; + int chan, tgt; uint32_t handle; - - MEMZERO(&mbs, sizeof (mbs)); + va_list ap; switch (ctl) { - default: - isp_prt(isp, ISP_LOGERR, "Unknown Control Opcode 0x%x", ctl); - break; - case ISPCTL_RESET_BUS: /* * Issue a bus reset. @@ -4308,60 +4477,128 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) break; } else if (IS_FC(isp)) { mbs.param[1] = 10; - bus = 0; + chan = 0; } else { - mbs.param[1] = SDPARAM(isp)->isp_bus_reset_delay; + va_start(ap, ctl); + chan = va_arg(ap, int); + va_end(ap); + mbs.param[1] = SDPARAM(isp, chan)->isp_bus_reset_delay; if (mbs.param[1] < 2) { mbs.param[1] = 2; } - bus = *((int *) arg); - if (IS_DUALBUS(isp)) { - mbs.param[2] = bus; - } + mbs.param[2] = chan; } - mbs.param[0] = MBOX_BUS_RESET; - isp->isp_sendmarker |= (1 << bus); - mbs.logval = MBLOGALL; + MBSINIT(&mbs, MBOX_BUS_RESET, MBLOGALL, 0); + ISP_SET_SENDMARKER(isp, chan, 1); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } isp_prt(isp, ISP_LOGINFO, - "driver initiated bus reset of bus %d", bus); + "driver initiated bus reset of bus %d", chan); return (0); case ISPCTL_RESET_DEV: - tgt = (*((int *) arg)) & 0xffff; + va_start(ap, ctl); + chan = va_arg(ap, int); + tgt = va_arg(ap, int); + va_end(ap); if (IS_24XX(isp)) { - isp_prt(isp, ISP_LOGWARN, "RESET DEV NOT IMPLEMENTED"); + uint8_t local[QENTRY_LEN]; + isp24xx_tmf_t *tmf; + isp24xx_statusreq_t *sp; + fcparam *fcp = FCPARAM(isp, chan); + fcportdb_t *lp; + int hdlidx; + + hdlidx = fcp->isp_dev_map[tgt] - 1; + if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { + isp_prt(isp, ISP_LOGWARN, + "Chan %d bad handle %d trying to reset" + "target %d", chan, hdlidx, tgt); + break; + } + lp = &fcp->portdb[hdlidx]; + if (lp->state != FC_PORTDB_STATE_VALID) { + isp_prt(isp, ISP_LOGWARN, + "Chan %d handle %d for abort of target %d " + "no longer valid", chan, + hdlidx, tgt); + break; + } + + tmf = (isp24xx_tmf_t *) local; + ISP_MEMZERO(tmf, QENTRY_LEN); + tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT; + tmf->tmf_header.rqs_entry_count = 1; + tmf->tmf_nphdl = lp->handle; + tmf->tmf_delay = 2; + tmf->tmf_timeout = 2; + tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET; + tmf->tmf_tidlo = lp->portid; + tmf->tmf_tidhi = lp->portid >> 16; + tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); + isp_prt(isp, ISP_LOGALL, "Chan %d Reset N-Port Handle 0x%04x @ Port 0x%06x", chan, lp->handle, lp->portid); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + break; + } + isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN); + fcp->sendmarker = 1; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp, chan); + break; + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, + QENTRY_LEN); + sp = (isp24xx_statusreq_t *) local; + isp_get_24xx_response(isp, + &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp); + FC_SCRATCH_RELEASE(isp, chan); + if (sp->req_completion_status == 0) { + return (0); + } + isp_prt(isp, ISP_LOGWARN, + "Chan %d reset of target %d returned 0x%x", + chan, tgt, sp->req_completion_status); break; } else if (IS_FC(isp)) { - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = tgt; mbs.ibits = (1 << 10); } else { mbs.param[1] = (tgt << 8); } - bus = 0; } else { - bus = (*((int *) arg)) >> 16; - mbs.param[1] = (bus << 15) | (tgt << 8); + mbs.param[1] = (chan << 15) | (tgt << 8); } - mbs.param[0] = MBOX_ABORT_TARGET; + MBSINIT(&mbs, MBOX_ABORT_TARGET, MBLOGALL, 0); mbs.param[2] = 3; /* 'delay', in seconds */ - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } isp_prt(isp, ISP_LOGINFO, - "Target %d on Bus %d Reset Succeeded", tgt, bus); - isp->isp_sendmarker |= (1 << bus); + "Target %d on Bus %d Reset Succeeded", tgt, chan); + ISP_SET_SENDMARKER(isp, chan, 1); return (0); case ISPCTL_ABORT_CMD: - xs = (XS_T *) arg; + va_start(ap, ctl); + xs = va_arg(ap, XS_T *); + va_end(ap); + tgt = XS_TGT(xs); + chan = XS_CHANNEL(xs); handle = isp_find_handle(isp, xs); if (handle == 0) { @@ -4370,11 +4607,74 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) break; } if (IS_24XX(isp)) { - isp_prt(isp, ISP_LOGWARN, "ABORT CMD NOT IMPLEMENTED"); + isp24xx_abrt_t local, *ab = &local, *ab2; + fcparam *fcp; + fcportdb_t *lp; + int hdlidx; + + fcp = FCPARAM(isp, chan); + hdlidx = fcp->isp_dev_map[tgt] - 1; + if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { + isp_prt(isp, ISP_LOGWARN, + "Chan %d bad handle %d trying to abort" + "target %d", chan, hdlidx, tgt); + break; + } + lp = &fcp->portdb[hdlidx]; + if (lp->state != FC_PORTDB_STATE_VALID) { + isp_prt(isp, ISP_LOGWARN, + "Chan %d handle %d for abort of target %d " + "no longer valid", chan, hdlidx, tgt); + break; + } + isp_prt(isp, ISP_LOGALL, + "Chan %d Abort Cmd for N-Port 0x%04x @ Port " + "0x%06x %p", chan, lp->handle, lp->portid, xs); + ISP_MEMZERO(ab, QENTRY_LEN); + ab->abrt_header.rqs_entry_type = RQSTYPE_ABORT_IO; + ab->abrt_header.rqs_entry_count = 1; + ab->abrt_handle = lp->handle; + ab->abrt_cmd_handle = handle; + ab->abrt_tidlo = lp->portid; + ab->abrt_tidhi = lp->portid >> 16; + ab->abrt_vpidx = ISP_GET_VPIDX(isp, chan); + + ISP_MEMZERO(&mbs, sizeof (mbs)); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + break; + } + isp_put_24xx_abrt(isp, ab, fcp->isp_scratch); + ab2 = (isp24xx_abrt_t *) + &((uint8_t *)fcp->isp_scratch)[QENTRY_LEN]; + ab2->abrt_nphdl = 0xdeaf; + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp, chan); + break; + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, + QENTRY_LEN); + isp_get_24xx_abrt(isp, ab2, ab); + FC_SCRATCH_RELEASE(isp, chan); + if (ab->abrt_nphdl == ISP24XX_ABRT_OKAY) { + return (0); + } + isp_prt(isp, ISP_LOGWARN, + "Chan %d handle %d abort returned 0x%x", chan, + hdlidx, ab->abrt_nphdl); break; } else if (IS_FC(isp)) { - if (FCPARAM(isp)->isp_sccfw) { - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_SCCFW(isp)) { + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = tgt; } else { mbs.param[1] = tgt << 8; @@ -4384,12 +4684,10 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) mbs.param[1] = tgt << 8 | XS_LUN(xs); } } else { - bus = XS_CHANNEL(xs); - mbs.param[1] = (bus << 15) | (tgt << 8) | XS_LUN(xs); + mbs.param[1] = (chan << 15) | (tgt << 8) | XS_LUN(xs); } - mbs.param[0] = MBOX_ABORT; + MBSINIT(&mbs, MBOX_ABORT, MBLOGALL & ~MBOX_COMMAND_ERROR, 0); mbs.param[2] = handle; - mbs.logval = MBLOGALL & ~MBOX_COMMAND_ERROR; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; @@ -4398,49 +4696,64 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) case ISPCTL_UPDATE_PARAMS: - isp_update(isp); + va_start(ap, ctl); + chan = va_arg(ap, int); + va_end(ap); + isp_spi_update(isp, chan); return (0); case ISPCTL_FCLINK_TEST: if (IS_FC(isp)) { - int usdelay = *((int *) arg); + int usdelay; + va_start(ap, ctl); + chan = va_arg(ap, int); + usdelay = va_arg(ap, int); + va_end(ap); if (usdelay == 0) { usdelay = 250000; } - return (isp_fclink_test(isp, usdelay)); + return (isp_fclink_test(isp, chan, usdelay)); } break; case ISPCTL_SCAN_FABRIC: if (IS_FC(isp)) { - return (isp_scan_fabric(isp)); + va_start(ap, ctl); + chan = va_arg(ap, int); + va_end(ap); + return (isp_scan_fabric(isp, chan)); } break; case ISPCTL_SCAN_LOOP: if (IS_FC(isp)) { - return (isp_scan_loop(isp)); + va_start(ap, ctl); + chan = va_arg(ap, int); + va_end(ap); + return (isp_scan_loop(isp, chan)); } break; case ISPCTL_PDB_SYNC: if (IS_FC(isp)) { - return (isp_pdb_sync(isp)); + va_start(ap, ctl); + chan = va_arg(ap, int); + va_end(ap); + return (isp_pdb_sync(isp, chan)); } break; case ISPCTL_SEND_LIP: if (IS_FC(isp) && !IS_24XX(isp)) { - mbs.param[0] = MBOX_INIT_LIP; - if (FCPARAM(isp)->isp_2klogin) { + MBSINIT(&mbs, MBOX_INIT_LIP, MBLOGALL, 0); + if (ISP_CAP_2KLOGIN(isp)) { mbs.ibits = (1 << 10); } - mbs.logval = MBLOGALL; isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { return (0); @@ -4449,42 +4762,66 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) break; case ISPCTL_GET_PDB: - if (IS_FC(isp) && arg) { - int id = *((int *)arg); - isp_pdb_t *pdb = arg; - return (isp_getpdb(isp, id, pdb, 1)); + if (IS_FC(isp)) { + isp_pdb_t *pdb; + va_start(ap, ctl); + chan = va_arg(ap, int); + tgt = va_arg(ap, int); + pdb = va_arg(ap, isp_pdb_t *); + va_end(ap); + return (isp_getpdb(isp, chan, tgt, pdb, 1)); } break; - case ISPCTL_GET_PORTNAME: + case ISPCTL_GET_NAMES: { - uint64_t *wwnp = arg; - int loopid = *wwnp; - *wwnp = isp_get_portname(isp, loopid, 0); - if (*wwnp == (uint64_t) -1) { + uint64_t *wwnn, *wwnp; + va_start(ap, ctl); + chan = va_arg(ap, int); + tgt = va_arg(ap, int); + wwnn = va_arg(ap, uint64_t *); + wwnp = va_arg(ap, uint64_t *); + va_end(ap); + if (wwnn == NULL && wwnp == NULL) { break; - } else { - return (0); } + if (wwnn) { + *wwnn = isp_get_wwn(isp, chan, tgt, 1); + if (*wwnn == INI_NONE) { + break; + } + } + if (wwnp) { + *wwnp = isp_get_wwn(isp, chan, tgt, 0); + if (*wwnp == INI_NONE) { + break; + } + } + return (0); } case ISPCTL_RUN_MBOXCMD: - - isp_mboxcmd(isp, arg); - return(0); - + { + va_start(ap, ctl); + mbr = va_arg(ap, mbreg_t *); + va_end(ap); + isp_mboxcmd(isp, mbr); + return (0); + } case ISPCTL_PLOGX: { - isp_plcmd_t *p = arg; + isp_plcmd_t *p; int r; - if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || - (p->handle != NIL_HANDLE)) { - return (isp_plogx(isp, p->handle, p->portid, - p->flags, 0)); + va_start(ap, ctl); + p = va_arg(ap, isp_plcmd_t *); + va_end(ap); + + if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || (p->handle != NIL_HANDLE)) { + return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0)); } do { - p->handle = isp_nxt_handle(isp, p->handle); - r = isp_plogx(isp, p->handle, p->portid, p->flags, 0); + p->handle = isp_nxt_handle(isp, p->channel, p->handle); + r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0); if ((r & 0xffff) == MBOX_PORT_ID_USED) { p->handle = r >> 16; r = 0; @@ -4493,28 +4830,10 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) } while ((r & 0xffff) == MBOX_LOOP_ID_USED); return (r); } -#ifdef ISP_TARGET_MODE - case ISPCTL_TOGGLE_TMODE: - { + default: + isp_prt(isp, ISP_LOGERR, "Unknown Control Opcode 0x%x", ctl); + break; - /* - * We don't check/set against role here- that's the - * responsibility for the outer layer to coordinate. - */ - if (IS_SCSI(isp)) { - int param = *(int *)arg; - mbs.param[0] = MBOX_ENABLE_TARGET_MODE; - mbs.param[1] = param & 0xffff; - mbs.param[2] = param >> 16; - mbs.logval = MBLOGALL; - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - break; - } - } - return (0); - } -#endif } return (-1); } @@ -4548,6 +4867,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) * The mailbox semaphore will be nonzero if so. */ if (sema) { + fmbox: if (mbox & 0x4000) { isp->isp_intmboxc++; if (isp->isp_mboxbsy) { @@ -4557,8 +4877,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) if ((obits & (1 << i)) == 0) { continue; } - isp->isp_mboxtmp[i] = - ISP_READ(isp, MBOX_OFF(i)); + isp->isp_mboxtmp[i] = ISP_READ(isp, MBOX_OFF(i)); } if (isp->isp_mbxwrk0) { if (isp_mbox_continue(isp) == 0) { @@ -4567,14 +4886,12 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } MBOX_NOTIFY_COMPLETE(isp); } else { - isp_prt(isp, ISP_LOGWARN, - "mailbox cmd (0x%x) with no waiters", mbox); + isp_prt(isp, ISP_LOGWARN, "mailbox cmd (0x%x) with no waiters", mbox); } } else if (isp_parse_async(isp, mbox) < 0) { return; } - if ((IS_FC(isp) && mbox != ASYNC_RIO_RESP) || - isp->isp_state != ISP_RUNSTATE) { + if ((IS_FC(isp) && mbox != ASYNC_RIO_RESP) || isp->isp_state != ISP_RUNSTATE) { goto out; } } @@ -4583,13 +4900,17 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) * We can't be getting this now. */ if (isp->isp_state != ISP_RUNSTATE) { - isp_prt(isp, ISP_LOGINFO, - "interrupt (ISR=%x SEMA=%x) when not ready", isr, sema); + /* + * This seems to happen to 23XX and 24XX cards- don't know why. + */ + if (isp->isp_mboxbsy && isp->isp_lastmbxcmd == MBOX_ABOUT_FIRMWARE) { + goto fmbox; + } + isp_prt(isp, ISP_LOGINFO, "interrupt (ISR=%x SEMA=%x) when not ready", isr, sema); /* * Thank you very much! *Burrrp*! */ - ISP_WRITE(isp, isp->isp_respoutrp, - ISP_READ(isp, isp->isp_respinrp)); + ISP_WRITE(isp, isp->isp_respoutrp, ISP_READ(isp, isp->isp_respinrp)); if (IS_24XX(isp)) { ISP_DISABLE_INTS(isp); } @@ -4600,12 +4921,10 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) /* * Check for ATIO Queue entries. */ - if (isp->isp_rspbsy == 0 && (isp->isp_role & ISP_ROLE_TARGET) && - IS_24XX(isp)) { - iptr = ISP_READ(isp, isp->isp_atioinrp); - optr = ISP_READ(isp, isp->isp_atiooutrp); + if (IS_24XX(isp)) { + iptr = ISP_READ(isp, BIU2400_ATIO_RSPINP); + optr = ISP_READ(isp, BIU2400_ATIO_RSPOUTP); - isp->isp_rspbsy = 1; while (optr != iptr) { uint8_t qe[QENTRY_LEN]; isphdr_t *hp; @@ -4623,14 +4942,12 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) (void) isp_target_notify(isp, addr, &oop); break; default: - isp_print_qentry(isp, "?ATIOQ entry?", - oop, addr); + isp_print_qentry(isp, "?ATIOQ entry?", oop, addr); break; } optr = ISP_NXT_QENTRY(oop, RESULT_QUEUE_LEN(isp)); - ISP_WRITE(isp, isp->isp_atiooutrp, optr); + ISP_WRITE(isp, BIU2400_ATIO_RSPOUTP, optr); } - isp->isp_rspbsy = 0; optr = isp->isp_residx; } #endif @@ -4646,9 +4963,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) * Debug: to be taken out eventually */ if (isp->isp_residx != optr) { - isp_prt(isp, ISP_LOGINFO, - "isp_intr: hard optr=%x, soft optr %x", - optr, isp->isp_residx); + isp_prt(isp, ISP_LOGINFO, "isp_intr: hard optr=%x, soft optr %x", optr, isp->isp_residx); isp->isp_residx = optr; } } else { @@ -4669,9 +4984,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } while (junk != iptr && ++i < 1000); if (iptr != junk) { - isp_prt(isp, ISP_LOGWARN, - "Response Queue Out Pointer Unstable (%x, %x)", - iptr, junk); + isp_prt(isp, ISP_LOGWARN, "Response Queue Out Pointer Unstable (%x, %x)", iptr, junk); goto out; } } else { @@ -4692,7 +5005,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) if (IS_24XX(isp)) { junk = 0; } else if (IS_23XX(isp)) { - USEC_DELAY(100); + ISP_DELAY(100); iptr = ISP_READ(isp, isp->isp_respinrp); junk = ISP_READ(isp, BIU_R2HSTSLO); } else { @@ -4709,18 +5022,11 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } } isp->isp_intbogus++; - isp_prt(isp, ISP_LOGDEBUG1, - "bogus intr- isr %x (%x) iptr %x optr %x", - isr, junk, iptr, optr); + isp_prt(isp, ISP_LOGDEBUG1, "bogus intr- isr %x (%x) iptr %x optr %x", isr, junk, iptr, optr); } } isp->isp_resodx = iptr; - - if (isp->isp_rspbsy) { - goto out; - } - isp->isp_rspbsy = 1; while (optr != iptr) { uint8_t qe[QENTRY_LEN]; ispstatusreq_t *sp = (ispstatusreq_t *) qe; @@ -4749,11 +5055,9 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) if (IS_24XX(isp) && etype == RQSTYPE_RESPONSE) { isp24xx_statusreq_t *sp2 = (isp24xx_statusreq_t *)qe; - isp_get_24xx_response(isp, - (isp24xx_statusreq_t *)hp, sp2); + isp_get_24xx_response(isp, (isp24xx_statusreq_t *)hp, sp2); if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, - "Response Queue Entry", QENTRY_LEN, sp2); + isp_print_bytes(isp, "Response Queue Entry", QENTRY_LEN, sp2); } scsi_status = sp2->req_scsi_status; completion_status = sp2->req_completion_status; @@ -4762,8 +5066,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } else if (etype == RQSTYPE_RESPONSE) { isp_get_response(isp, (ispstatusreq_t *) hp, sp); if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, - "Response Queue Entry", QENTRY_LEN, sp); + isp_print_bytes(isp, "Response Queue Entry", QENTRY_LEN, sp); } scsi_status = sp->req_scsi_status; completion_status = sp->req_completion_status; @@ -4774,17 +5077,15 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) isp_rio2_t *rio = (isp_rio2_t *)qe; isp_get_rio2(isp, (isp_rio2_t *) hp, rio); if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, - "Response Queue Entry", QENTRY_LEN, rio); + isp_print_bytes(isp, "Response Queue Entry", QENTRY_LEN, rio); } for (i = 0; i < rio->req_header.rqs_seqno; i++) { isp_fastpost_complete(isp, rio->req_handles[i]); } if (isp->isp_fpcchiwater < rio->req_header.rqs_seqno) { - isp->isp_fpcchiwater = - rio->req_header.rqs_seqno; + isp->isp_fpcchiwater = rio->req_header.rqs_seqno; } - MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } else { /* @@ -4793,13 +5094,22 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) * us, so we reload our goal index. */ int r; - r = isp_handle_other_response(isp, etype, hp, &optr); + uint32_t tsto = oop; + r = isp_handle_other_response(isp, etype, hp, &tsto); if (r < 0) { goto read_again; } + /* + * If somebody updated the output pointer, then reset + * optr to be one more than the updated amount. + */ + while (tsto != oop) { + optr = ISP_NXT_QENTRY(tsto, + RESULT_QUEUE_LEN(isp)); + } if (r > 0) { - iptr = isp->isp_resodx; - MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_WRITE(isp, isp->isp_respoutrp, optr); + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } @@ -4819,7 +5129,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) etype, oop, optr, nlooked); isp_print_bytes(isp, "Request Queue Entry", QENTRY_LEN, sp); - MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } buddaboom = 1; @@ -4832,35 +5142,38 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) if (sp->req_header.rqs_flags & RQSFLAG_MASK) { if (sp->req_header.rqs_flags & RQSFLAG_CONTINUATION) { - isp_prt(isp, ISP_LOGWARN, - "continuation segment"); + isp_print_bytes(isp, "unexpected continuation segment", QENTRY_LEN, sp); ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } if (sp->req_header.rqs_flags & RQSFLAG_FULL) { - isp_prt(isp, ISP_LOGDEBUG1, - "internal queues full"); + isp_prt(isp, ISP_LOGDEBUG0, "internal queues full"); /* * We'll synthesize a QUEUE FULL message below. */ } if (sp->req_header.rqs_flags & RQSFLAG_BADHEADER) { - isp_print_bytes(isp, "bad header flag", - QENTRY_LEN, sp); + isp_print_bytes(isp, "bad header flag", QENTRY_LEN, sp); buddaboom++; } if (sp->req_header.rqs_flags & RQSFLAG_BADPACKET) { - isp_print_bytes(isp, "bad request packet", - QENTRY_LEN, sp); + isp_print_bytes(isp, "bad request packet", QENTRY_LEN, sp); buddaboom++; } + if (sp->req_header.rqs_flags & RQSFLAG_BADCOUNT) { + isp_print_bytes(isp, "invalid entry count", QENTRY_LEN, sp); + buddaboom++; + } + if (sp->req_header.rqs_flags & RQSFLAG_BADORDER) { + isp_print_bytes(isp, "invalid IOCB ordering", QENTRY_LEN, sp); + ISP_WRITE(isp, isp->isp_respoutrp, optr); + continue; + } } - if (sp->req_handle > isp->isp_maxcmds || sp->req_handle < 1) { - isp_prt(isp, ISP_LOGERR, - "bad request handle %d (type 0x%x)", - sp->req_handle, etype); - MEMZERO(hp, QENTRY_LEN); /* PERF */ + if ((sp->req_handle != ISP_SPCL_HANDLE) && (sp->req_handle > isp->isp_maxcmds || sp->req_handle < 1)) { + isp_prt(isp, ISP_LOGERR, "bad request handle %d (type 0x%x)", sp->req_handle, etype); + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } @@ -4869,25 +5182,21 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) uint8_t ts = completion_status & 0xff; /* * Only whine if this isn't the expected fallout of - * aborting the command. + * aborting the command or resetting the target. */ if (etype != RQSTYPE_RESPONSE) { - isp_prt(isp, ISP_LOGERR, - "cannot find handle 0x%x (type 0x%x)", - sp->req_handle, etype); - } else if (ts != RQCS_ABORTED) { - isp_prt(isp, ISP_LOGERR, - "cannot find handle 0x%x (status 0x%x)", - sp->req_handle, ts); + isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (type 0x%x)", sp->req_handle, etype); + } else if (ts != RQCS_ABORTED && ts != RQCS_RESET_OCCURRED && sp->req_handle != ISP_SPCL_HANDLE) { + isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (status 0x%x)", sp->req_handle, ts); } - MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } isp_destroy_handle(isp, sp->req_handle); if (req_status_flags & RQSTF_BUS_RESET) { XS_SETERR(xs, HBA_BUSRESET); - isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 1); } if (buddaboom) { XS_SETERR(xs, HBA_BOTCH); @@ -4912,11 +5221,9 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) */ req_state_flags |= RQSF_GOT_STATUS|RQSF_GOT_SENSE; if (IS_24XX(isp)) { - snsp = - ((isp24xx_statusreq_t *)sp)->req_rsp_sense; + snsp = ((isp24xx_statusreq_t *)sp)->req_rsp_sense; snsp += rlen; - slen = - ((isp24xx_statusreq_t *)sp)->req_sense_len; + slen = ((isp24xx_statusreq_t *)sp)->req_sense_len; } else { snsp = sp->req_sense_data; slen = sp->req_sense_len; @@ -4931,27 +5238,38 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) switch (etype) { case RQSTYPE_RESPONSE: - XS_SET_STATE_STAT(isp, xs, sp); - if (resp && rlen >= 4 && - resp[FCP_RSPNS_CODE_OFFSET] != 0) { - isp_prt(isp, ISP_LOGWARN, - "%d.%d.%d FCP RESPONSE: 0x%x", - XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), - resp[FCP_RSPNS_CODE_OFFSET]); - XS_SETERR(xs, HBA_BOTCH); + if (resp && rlen >= 4 && resp[FCP_RSPNS_CODE_OFFSET] != 0) { + const char *ptr; + char lb[64]; + const char *rnames[6] = { + "Task Management Function Done", + "Data Length Differs From Burst Length", + "Invalid FCP Cmnd", + "FCP DATA RO mismatch with FCP DATA_XFR_RDY RO", + "Task Management Function Rejected", + "Task Management Function Failed", + }; + if (resp[FCP_RSPNS_CODE_OFFSET] > 5) { + ISP_SNPRINTF(lb, sizeof lb, "Unknown FCP Response Code 0x%x", resp[FCP_RSPNS_CODE_OFFSET]); + ptr = lb; + } else { + ptr = rnames[resp[FCP_RSPNS_CODE_OFFSET]]; + } + isp_prt(isp, ISP_LOGWARN, "%d.%d.%d FCP RESPONSE, LENGTH %u: %s CDB0=0x%02x", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), rlen, ptr, XS_CDBP(xs)[0] & 0xff); + if (resp[FCP_RSPNS_CODE_OFFSET] != 0) { + XS_SETERR(xs, HBA_BOTCH); + } } if (IS_24XX(isp)) { - isp_parse_status_24xx(isp, - (isp24xx_statusreq_t *)sp, xs, &resid); + isp_parse_status_24xx(isp, (isp24xx_statusreq_t *)sp, xs, &resid); } else { isp_parse_status(isp, (void *)sp, xs, &resid); } - if ((XS_NOERR(xs) || XS_ERR(xs) == HBA_NOERROR) && - (*XS_STSP(xs) == SCSI_BUSY)) { + if ((XS_NOERR(xs) || XS_ERR(xs) == HBA_NOERROR) && (*XS_STSP(xs) == SCSI_BUSY)) { XS_SETERR(xs, HBA_TGTBSY); } if (IS_SCSI(isp)) { - XS_RESID(xs) = resid; + XS_SET_RESID(xs, resid); /* * A new synchronous rate was negotiated for * this target. Mark state such that we'll go @@ -4959,56 +5277,45 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) */ if (req_status_flags & RQSTF_NEGOTIATION) { int t = XS_TGT(xs); - sdparam *sdp = isp->isp_param; - sdp += XS_CHANNEL(xs); + sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); sdp->isp_devparam[t].dev_refresh = 1; - isp->isp_update |= - (1 << XS_CHANNEL(xs)); + sdp->update = 1; } } else { if (req_status_flags & RQSF_XFER_COMPLETE) { - XS_RESID(xs) = 0; + XS_SET_RESID(xs, 0); } else if (scsi_status & RQCS_RESID) { - XS_RESID(xs) = resid; + XS_SET_RESID(xs, resid); } else { - XS_RESID(xs) = 0; + XS_SET_RESID(xs, 0); } } if (snsp && slen) { XS_SAVE_SENSE(xs, snsp, slen); + } else if ((req_status_flags & RQSF_GOT_STATUS) && (scsi_status & 0xff) == SCSI_CHECK && IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, "CHECK CONDITION w/o sense data for CDB=0x%x", XS_CDBP(xs)[0] & 0xff); + isp_print_bytes(isp, "CC with no Sense", QENTRY_LEN, qe); } - isp_prt(isp, ISP_LOGDEBUG2, - "asked for %ld got raw resid %ld settled for %ld", - (long) XS_XFRLEN(xs), resid, (long) XS_RESID(xs)); + isp_prt(isp, ISP_LOGDEBUG2, "asked for %ld got raw resid %ld settled for %ld", (long) XS_XFRLEN(xs), resid, (long) XS_GET_RESID(xs)); break; case RQSTYPE_REQUEST: case RQSTYPE_A64: case RQSTYPE_T2RQS: case RQSTYPE_T3RQS: case RQSTYPE_T7RQS: - if (sp->req_header.rqs_flags & RQSFLAG_FULL) { + if (!IS_24XX(isp) && (sp->req_header.rqs_flags & RQSFLAG_FULL)) { /* * Force Queue Full status. */ *XS_STSP(xs) = SCSI_QFULL; XS_SETERR(xs, HBA_NOERROR); } else if (XS_NOERR(xs)) { - /* - * ???? - */ XS_SETERR(xs, HBA_BOTCH); - isp_prt(isp, ISP_LOGDEBUG0, - "Request Queue Entry bounced back"); - if ((isp->isp_dblev & ISP_LOGDEBUG1) == 0) { - isp_print_bytes(isp, "Bounced Request", - QENTRY_LEN, qe); - } } - XS_RESID(xs) = XS_XFRLEN(xs); + XS_SET_RESID(xs, XS_XFRLEN(xs)); break; default: - isp_print_bytes(isp, "Unhandled Response Type", - QENTRY_LEN, qe); + isp_print_bytes(isp, "Unhandled Response Type", QENTRY_LEN, qe); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BOTCH); } @@ -5023,7 +5330,7 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) ISP_DMAFREE(isp, xs, sp->req_handle); } - if (((isp->isp_dblev & (ISP_LOGDEBUG2|ISP_LOGDEBUG3))) || + if (((isp->isp_dblev & (ISP_LOGDEBUG1|ISP_LOGDEBUG2|ISP_LOGDEBUG3))) || ((isp->isp_dblev & ISP_LOGDEBUG0) && ((!XS_NOERR(xs)) || (*XS_STSP(xs) != SCSI_GOOD)))) { char skey; @@ -5039,14 +5346,15 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) skey = '.'; } isp_prt(isp, ISP_LOGALL, finmsg, XS_CHANNEL(xs), - XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs), XS_RESID(xs), + XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs), (long) XS_GET_RESID(xs), *XS_STSP(xs), skey, XS_ERR(xs)); } - if (isp->isp_nactive > 0) + if (isp->isp_nactive > 0) { isp->isp_nactive--; + } complist[ndone++] = xs; /* defer completion call until later */ - MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ if (ndone == MAX_REQUESTQ_COMPLETIONS) { break; } @@ -5078,7 +5386,6 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) } isp->isp_residx = optr; - isp->isp_rspbsy = 0; for (i = 0; i < ndone; i++) { xs = complist[i]; if (xs) { @@ -5092,34 +5399,50 @@ isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) * Support routines. */ +#define GET_24XX_BUS(isp, chan, msg) \ + if (IS_24XX(isp)) { \ + chan = ISP_READ(isp, OUTMAILBOX3) & 0xff; \ + if (chan >= isp->isp_nchan) { \ + isp_prt(isp, ISP_LOGERR, "bogus channel %u for %s at line %d", chan, msg, __LINE__); \ + break; \ + } \ + } + static int isp_parse_async(ispsoftc_t *isp, uint16_t mbox) { int rval = 0; - int bus; + int pattern = 0; + uint16_t chan; if (IS_DUALBUS(isp)) { - bus = ISP_READ(isp, OUTMAILBOX6); + chan = ISP_READ(isp, OUTMAILBOX6); } else { - bus = 0; + chan = 0; } isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox); switch (mbox) { case ASYNC_BUS_RESET: - isp->isp_sendmarker |= (1 << bus); + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_BUS_RESET for FC card"); + break; + } + ISP_SET_SENDMARKER(isp, chan, 1); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { + if (isp_target_async(isp, chan, mbox)) { rval = -1; } #endif - isp_async(isp, ISPASYNC_BUS_RESET, &bus); + isp_async(isp, ISPASYNC_BUS_RESET, chan); break; case ASYNC_SYSTEM_ERROR: + isp->isp_dead = 1; isp->isp_state = ISP_CRASHED; if (IS_FC(isp)) { - FCPARAM(isp)->isp_loopstate = LOOP_NIL; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; + FCPARAM(isp, chan)->isp_loopstate = LOOP_NIL; + FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT; } /* * Were we waiting for a mailbox command to complete? @@ -5134,7 +5457,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) * It's up to the handler for isp_async to reinit stuff and * restart the firmware */ - isp_async(isp, ISPASYNC_FW_CRASH, NULL); + isp_async(isp, ISPASYNC_FW_CRASH); rval = -1; break; @@ -5147,6 +5470,17 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) break; case ASYNC_QWAKEUP: +#ifdef ISP_TARGET_MODE + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGERR, "ATIO Queue Transfer Error"); + break; + } +#endif + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_QWAKEUP for FC card"); + break; + } /* * We've just been notified that the Queue has woken up. * We don't need to be chatty about this- just unlatch things @@ -5156,66 +5490,101 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) break; case ASYNC_TIMEOUT_RESET: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_TIMEOUT_RESET for FC card"); + break; + } isp_prt(isp, ISP_LOGWARN, - "timeout initiated SCSI bus reset of bus %d", bus); - isp->isp_sendmarker |= (1 << bus); + "timeout initiated SCSI bus reset of chan %d", chan); + ISP_SET_SENDMARKER(isp, chan, 1); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { + if (isp_target_async(isp, chan, mbox)) { rval = -1; } #endif break; case ASYNC_DEVICE_RESET: - isp_prt(isp, ISP_LOGINFO, "device reset on bus %d", bus); - isp->isp_sendmarker |= (1 << bus); + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL DEVICE_RESET for FC card"); + break; + } + isp_prt(isp, ISP_LOGINFO, "device reset on chan %d", chan); + ISP_SET_SENDMARKER(isp, chan, 1); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { + if (isp_target_async(isp, chan, mbox)) { rval = -1; } #endif break; case ASYNC_EXTMSG_UNDERRUN: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_EXTMSG_UNDERRUN for FC card"); + break; + } isp_prt(isp, ISP_LOGWARN, "extended message underrun"); break; case ASYNC_SCAM_INT: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_SCAM_INT for FC card"); + break; + } isp_prt(isp, ISP_LOGINFO, "SCAM interrupt"); break; case ASYNC_HUNG_SCSI: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_HUNG_SCSI for FC card"); + break; + } isp_prt(isp, ISP_LOGERR, "stalled SCSI Bus after DATA Overrun"); /* XXX: Need to issue SCSI reset at this point */ break; case ASYNC_KILLED_BUS: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_KILLED_BUS for FC card"); + break; + } isp_prt(isp, ISP_LOGERR, "SCSI Bus reset after DATA Overrun"); break; case ASYNC_BUS_TRANSIT: + if (IS_FC(isp)) { + isp_prt(isp, ISP_LOGWARN, + "ILLEGAL ASYNC_BUS_TRANSIT for FC card"); + break; + } mbox = ISP_READ(isp, OUTMAILBOX2); switch (mbox & 0x1c00) { case SXP_PINS_LVD_MODE: isp_prt(isp, ISP_LOGINFO, "Transition to LVD mode"); - SDPARAM(isp)->isp_diffmode = 0; - SDPARAM(isp)->isp_ultramode = 0; - SDPARAM(isp)->isp_lvdmode = 1; + SDPARAM(isp, chan)->isp_diffmode = 0; + SDPARAM(isp, chan)->isp_ultramode = 0; + SDPARAM(isp, chan)->isp_lvdmode = 1; break; case SXP_PINS_HVD_MODE: isp_prt(isp, ISP_LOGINFO, "Transition to Differential mode"); - SDPARAM(isp)->isp_diffmode = 1; - SDPARAM(isp)->isp_ultramode = 0; - SDPARAM(isp)->isp_lvdmode = 0; + SDPARAM(isp, chan)->isp_diffmode = 1; + SDPARAM(isp, chan)->isp_ultramode = 0; + SDPARAM(isp, chan)->isp_lvdmode = 0; break; case SXP_PINS_SE_MODE: isp_prt(isp, ISP_LOGINFO, "Transition to Single Ended mode"); - SDPARAM(isp)->isp_diffmode = 0; - SDPARAM(isp)->isp_ultramode = 1; - SDPARAM(isp)->isp_lvdmode = 0; + SDPARAM(isp, chan)->isp_diffmode = 0; + SDPARAM(isp, chan)->isp_ultramode = 1; + SDPARAM(isp, chan)->isp_lvdmode = 0; break; default: isp_prt(isp, ISP_LOGWARN, @@ -5226,32 +5595,28 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) * XXX: Set up to renegotiate again! */ /* Can only be for a 1080... */ - isp->isp_sendmarker |= (1 << bus); + ISP_SET_SENDMARKER(isp, chan, 1); break; - /* - * We can use bus, which will always be zero for FC cards, - * as a mailbox pattern accumulator to be checked below. - */ case ASYNC_RIO5: - bus = 0x1ce; /* outgoing mailbox regs 1-3, 6-7 */ + pattern = 0xce; /* outgoing mailbox regs 1-3, 6-7 */ break; case ASYNC_RIO4: - bus = 0x14e; /* outgoing mailbox regs 1-3, 6 */ + pattern = 0x4e; /* outgoing mailbox regs 1-3, 6 */ break; case ASYNC_RIO3: - bus = 0x10e; /* outgoing mailbox regs 1-3 */ + pattern = 0x0e; /* outgoing mailbox regs 1-3 */ break; case ASYNC_RIO2: - bus = 0x106; /* outgoing mailbox regs 1-2 */ + pattern = 0x06; /* outgoing mailbox regs 1-2 */ break; case ASYNC_RIO1: case ASYNC_CMD_CMPLT: - bus = 0x102; /* outgoing mailbox regs 1 */ + pattern = 0x02; /* outgoing mailbox regs 1 */ break; case ASYNC_RIO_RESP: @@ -5260,8 +5625,15 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) case ASYNC_CTIO_DONE: { #ifdef ISP_TARGET_MODE - int handle = - (ISP_READ(isp, OUTMAILBOX2) << 16) | + int handle; + if (IS_SCSI(isp) || IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad ASYNC_CTIO_DONE for %s cards", + IS_SCSI(isp)? "SCSI" : "24XX"); + break; + } + handle = + (ISP_READ(isp, OUTMAILBOX2) << 16) | (ISP_READ(isp, OUTMAILBOX1)); if (isp_target_async(isp, handle, mbox)) { rval = -1; @@ -5270,6 +5642,12 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp->isp_fphccmplt++; } #else + if (IS_SCSI(isp) || IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad ASYNC_CTIO_DONE for %s cards", + IS_SCSI(isp)? "SCSI" : "24XX"); + break; + } isp_prt(isp, ISP_LOGINFO, "Fast Posting CTIO done"); isp->isp_fphccmplt++; /* count it as a fast posting intr */ #endif @@ -5278,114 +5656,236 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) case ASYNC_LIP_ERROR: case ASYNC_LIP_F8: case ASYNC_LIP_OCCURRED: - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; - isp->isp_sendmarker = 1; - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_LIP, NULL); -#ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { - rval = -1; + case ASYNC_PTPMODE: + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad LIP event for SCSI cards"); + break; } -#endif /* - * We've had problems with data corruption occuring on - * commands that complete (with no apparent error) after - * we receive a LIP. This has been observed mostly on - * Local Loop topologies. To be safe, let's just mark - * all active commands as dead. + * These are broadcast events that have to be sent across + * all active channels. */ - if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || - FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { - int i, j; - for (i = j = 0; i < isp->isp_maxcmds; i++) { - XS_T *xs; - xs = isp->isp_xflist[i]; - if (xs != NULL) { + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + int topo = fcp->isp_topo; + + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_LIP_RCVD; + ISP_SET_SENDMARKER(isp, chan, 1); + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_LIP, chan); +#ifdef ISP_TARGET_MODE + if (isp_target_async(isp, chan, mbox)) { + rval = -1; + } +#endif + /* + * We've had problems with data corruption occuring on + * commands that complete (with no apparent error) after + * we receive a LIP. This has been observed mostly on + * Local Loop topologies. To be safe, let's just mark + * all active commands as dead. + */ + if (topo == TOPO_NL_PORT || topo == TOPO_FL_PORT) { + int i, j; + for (i = j = 0; i < isp->isp_maxcmds; i++) { + XS_T *xs; + xs = isp->isp_xflist[i]; + if (xs == NULL) { + continue; + } + if (XS_CHANNEL(xs) != chan) { + continue; + } j++; XS_SETERR(xs, HBA_BUSRESET); } - } - if (j) { - isp_prt(isp, ISP_LOGERR, - "LIP destroyed %d active commands", j); + if (j) { + isp_prt(isp, ISP_LOGERR, lipd, chan, j); + } } } break; case ASYNC_LOOP_UP: - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_LOOP_UP, NULL); -#ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { - rval = -1; + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad LOOP UP event for SCSI cards"); + break; } + /* + * This is a broadcast event that has to be sent across + * all active channels. + */ + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + + ISP_SET_SENDMARKER(isp, chan, 1); + + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_LIP_RCVD; + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_LOOP_UP, chan); +#ifdef ISP_TARGET_MODE + if (isp_target_async(isp, chan, mbox)) { + rval = -1; + } #endif + } break; case ASYNC_LOOP_DOWN: - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_NIL; - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_LOOP_DOWN, NULL); -#ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { - rval = -1; + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad LOOP DOWN event for SCSI cards"); + break; } + /* + * This is a broadcast event that has to be sent across + * all active channels. + */ + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + + ISP_SET_SENDMARKER(isp, chan, 1); + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_NIL; + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_LOOP_DOWN, chan); +#ifdef ISP_TARGET_MODE + if (isp_target_async(isp, chan, mbox)) { + rval = -1; + } #endif + } break; case ASYNC_LOOP_RESET: - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_NIL; - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_LOOP_RESET, NULL); -#ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { - rval = -1; + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad LIP RESET event for SCSI cards"); + break; } + /* + * This is a broadcast event that has to be sent across + * all active channels. + */ + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + + ISP_SET_SENDMARKER(isp, chan, 1); + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_NIL; + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_LOOP_RESET, chan); +#ifdef ISP_TARGET_MODE + if (isp_target_async(isp, chan, mbox)) { + rval = -1; + } #endif + } break; case ASYNC_PDB_CHANGED: - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_PDB); - break; - - case ASYNC_CHANGE_NOTIFY: - if (FCPARAM(isp)->isp_topo == TOPO_F_PORT) { - FCPARAM(isp)->isp_loopstate = LOOP_LSCAN_DONE; + { + int nphdl, nlstate, reason; + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad PDB CHANGED event for SCSI cards"); + break; + } + /* + * We *should* get a channel out of the 24XX, but we don't seem + * to get more than a PDB CHANGED on channel 0, so turn it into + * a broadcast event. + */ + if (IS_24XX(isp)) { + nphdl = ISP_READ(isp, OUTMAILBOX1); + nlstate = ISP_READ(isp, OUTMAILBOX2); + reason = ISP_READ(isp, OUTMAILBOX3) >> 8; } else { - FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; + nphdl = NIL_HANDLE; + nlstate = reason = 0; } - ISP_MARK_PORTDB(isp, 1); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_SNS); - break; + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); - case ASYNC_PTPMODE: - ISP_MARK_PORTDB(isp, 1); - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); -#ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) { - rval = -1; + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + ISP_SET_SENDMARKER(isp, chan, 1); + fcp->isp_loopstate = LOOP_PDB_RCVD; + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, + ISPASYNC_CHANGE_PDB, nphdl, nlstate, reason); } -#endif - isp_prt(isp, ISP_LOGINFO, "Point-to-Point mode"); break; + } + case ASYNC_CHANGE_NOTIFY: + { + int lochan, hichan; + + if (IS_SCSI(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad CHANGE NOTIFY event for SCSI cards"); + break; + } + if (ISP_FW_NEWER_THAN(isp, 4, 0, 25) && ISP_CAP_MULTI_ID(isp)) { + GET_24XX_BUS(isp, chan, "ASYNC_CHANGE_NOTIFY"); + lochan = chan; + hichan = chan + 1; + } else { + lochan = 0; + hichan = isp->isp_nchan; + } + for (chan = lochan; chan < hichan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + + if (fcp->role == ISP_ROLE_NONE) { + continue; + } + + if (fcp->isp_topo == TOPO_F_PORT) { + fcp->isp_loopstate = LOOP_LSCAN_DONE; + } else { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + ISP_MARK_PORTDB(isp, chan, 1); + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, + ISPASYNC_CHANGE_SNS); + } + break; + } case ASYNC_CONNMODE: + /* + * This only applies to 2100 amd 2200 cards + */ + if (!IS_2200(isp) && !IS_2100(isp)) { + isp_prt(isp, ISP_LOGWARN, + "bad card for ASYNC_CONNMODE event"); + break; + } + chan = 0; mbox = ISP_READ(isp, OUTMAILBOX1); - ISP_MARK_PORTDB(isp, 1); + ISP_MARK_PORTDB(isp, chan, 1); switch (mbox) { case ISP_CONN_LOOP: isp_prt(isp, ISP_LOGINFO, @@ -5400,8 +5900,10 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) "Point-to-Point -> Loop mode (BAD LIP)"); break; case ISP_CONN_FATAL: + isp->isp_dead = 1; + isp->isp_state = ISP_CRASHED; isp_prt(isp, ISP_LOGERR, "FATAL CONNECTION ERROR"); - isp_async(isp, ISPASYNC_FW_CRASH, NULL); + isp_async(isp, ISPASYNC_FW_CRASH); return (-1); case ISP_CONN_LOOPBACK: isp_prt(isp, ISP_LOGWARN, @@ -5412,12 +5914,21 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) "Unknown connection mode (0x%x)", mbox); break; } - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); - isp->isp_sendmarker = 1; - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, + ISPASYNC_CHANGE_OTHER); + FCPARAM(isp, chan)->sendmarker = 1; + FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT; + FCPARAM(isp, chan)->isp_loopstate = LOOP_LIP_RCVD; break; + case ASYNC_RCV_ERR: + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, "Receive Error"); + } else { + isp_prt(isp, ISP_LOGWARN, + "Unknown Async Code 0x%x", mbox); + } + break; case ASYNC_RJT_SENT: /* same as ASYNC_QFULL_SENT */ if (IS_24XX(isp)) { isp_prt(isp, ISP_LOGTDEBUG0, "LS_RJT sent"); @@ -5432,12 +5943,12 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) break; } - if (bus & 0x100) { + if (pattern) { int i, nh; uint16_t handles[16]; for (nh = 0, i = 1; i < MAX_MAILBOX(isp); i++) { - if ((bus & (1 << i)) == 0) { + if ((pattern & (1 << i)) == 0) { continue; } handles[nh++] = ISP_READ(isp, MBOX_OFF(i)); @@ -5493,9 +6004,18 @@ isp_handle_other_response(ispsoftc_t *isp, int type, } #endif /* FALLTHROUGH */ + case RQSTYPE_RPT_ID_ACQ: + if (IS_24XX(isp)) { + isp_ridacq_t rid; + isp_get_ridacq(isp, (isp_ridacq_t *)hp, &rid); + if (rid.ridacq_format == 0) { + } + return (1); + } + /* FALLTHROUGH */ case RQSTYPE_REQUEST: default: - USEC_DELAY(100); + ISP_DELAY(100); if (type != isp_get_response_type(isp, hp)) { /* * This is questionable- we're just papering over @@ -5511,9 +6031,6 @@ isp_handle_other_response(ispsoftc_t *isp, int type, } isp_prt(isp, ISP_LOGWARN, "Unhandled Response Type 0x%x", isp_get_response_type(isp, hp)); - if (isp_async(isp, ISPASYNC_UNHANDLED_RESPONSE, hp)) { - return (1); - } return (0); } } @@ -5554,52 +6071,52 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) case RQCS_TRANSPORT_ERROR: { char buf[172]; - SNPRINTF(buf, sizeof (buf), "states=>"); + ISP_SNPRINTF(buf, sizeof (buf), "states=>"); if (sp->req_state_flags & RQSF_GOT_BUS) { - SNPRINTF(buf, sizeof (buf), "%s GOT_BUS", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_BUS", buf); } if (sp->req_state_flags & RQSF_GOT_TARGET) { - SNPRINTF(buf, sizeof (buf), "%s GOT_TGT", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_TGT", buf); } if (sp->req_state_flags & RQSF_SENT_CDB) { - SNPRINTF(buf, sizeof (buf), "%s SENT_CDB", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s SENT_CDB", buf); } if (sp->req_state_flags & RQSF_XFRD_DATA) { - SNPRINTF(buf, sizeof (buf), "%s XFRD_DATA", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s XFRD_DATA", buf); } if (sp->req_state_flags & RQSF_GOT_STATUS) { - SNPRINTF(buf, sizeof (buf), "%s GOT_STS", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_STS", buf); } if (sp->req_state_flags & RQSF_GOT_SENSE) { - SNPRINTF(buf, sizeof (buf), "%s GOT_SNS", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_SNS", buf); } if (sp->req_state_flags & RQSF_XFER_COMPLETE) { - SNPRINTF(buf, sizeof (buf), "%s XFR_CMPLT", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s XFR_CMPLT", buf); } - SNPRINTF(buf, sizeof (buf), "%s\nstatus=>", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s\nstatus=>", buf); if (sp->req_status_flags & RQSTF_DISCONNECT) { - SNPRINTF(buf, sizeof (buf), "%s Disconnect", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Disconnect", buf); } if (sp->req_status_flags & RQSTF_SYNCHRONOUS) { - SNPRINTF(buf, sizeof (buf), "%s Sync_xfr", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Sync_xfr", buf); } if (sp->req_status_flags & RQSTF_PARITY_ERROR) { - SNPRINTF(buf, sizeof (buf), "%s Parity", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Parity", buf); } if (sp->req_status_flags & RQSTF_BUS_RESET) { - SNPRINTF(buf, sizeof (buf), "%s Bus_Reset", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Bus_Reset", buf); } if (sp->req_status_flags & RQSTF_DEVICE_RESET) { - SNPRINTF(buf, sizeof (buf), "%s Device_Reset", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Device_Reset", buf); } if (sp->req_status_flags & RQSTF_ABORTED) { - SNPRINTF(buf, sizeof (buf), "%s Aborted", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Aborted", buf); } if (sp->req_status_flags & RQSTF_TIMEOUT) { - SNPRINTF(buf, sizeof (buf), "%s Timeout", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Timeout", buf); } if (sp->req_status_flags & RQSTF_NEGOTIATION) { - SNPRINTF(buf, sizeof (buf), "%s Negotiation", buf); + ISP_SNPRINTF(buf, sizeof (buf), "%s Negotiation", buf); } isp_prt(isp, ISP_LOGERR, "%s", buf); isp_prt(isp, ISP_LOGERR, "transport error for %d.%d.%d:\n%s", @@ -5608,20 +6125,24 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) break; } case RQCS_RESET_OCCURRED: + { + int chan; isp_prt(isp, ISP_LOGWARN, "bus reset destroyed command for %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); - isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + for (chan = 0; chan < isp->isp_nchan; chan++) { + FCPARAM(isp, chan)->sendmarker = 1; + } if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BUSRESET); } *rp = XS_XFRLEN(xs); return; - + } case RQCS_ABORTED: isp_prt(isp, ISP_LOGERR, "command aborted for %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); - isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 1); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_ABORTED); } @@ -5639,9 +6160,9 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) return; case RQCS_DATA_OVERRUN: - XS_RESID(xs) = sp->req_resid; - isp_prt(isp, ISP_LOGERR, "data overrun for command on %d.%d.%d", - XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + XS_SET_RESID(xs, sp->req_resid); + isp_prt(isp, ISP_LOGERR, "data overrun (%ld) for command on %d.%d.%d", + (long) XS_GET_RESID(xs), XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_DATAOVR); } @@ -5733,7 +6254,7 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) return; } } - XS_RESID(xs) = sp->req_resid; + XS_SET_RESID(xs, sp->req_resid); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_NOERROR); } @@ -5804,11 +6325,10 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) "Wide Negotiation failed for %d.%d.%d", XS_TGT(xs), XS_LUN(xs), XS_CHANNEL(xs)); if (IS_SCSI(isp)) { - sdparam *sdp = isp->isp_param; - sdp += XS_CHANNEL(xs); + sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); sdp->isp_devparam[XS_TGT(xs)].goal_flags &= ~DPARM_WIDE; sdp->isp_devparam[XS_TGT(xs)].dev_update = 1; - isp->isp_update |= (1 << XS_CHANNEL(xs)); + sdp->update = 1; } if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_NOERROR); @@ -5820,11 +6340,11 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) "SDTR Message failed for target %d.%d.%d", XS_TGT(xs), XS_LUN(xs), XS_CHANNEL(xs)); if (IS_SCSI(isp)) { - sdparam *sdp = isp->isp_param; + sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); sdp += XS_CHANNEL(xs); sdp->isp_devparam[XS_TGT(xs)].goal_flags &= ~DPARM_SYNC; sdp->isp_devparam[XS_TGT(xs)].dev_update = 1; - isp->isp_update |= (1 << XS_CHANNEL(xs)); + sdp->update = 1; } break; @@ -5860,15 +6380,13 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) * to force a re-login of this unit. If we're on fabric, * then we'll have to log in again as a matter of course. */ - if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || - FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { + if (FCPARAM(isp, 0)->isp_topo == TOPO_NL_PORT || + FCPARAM(isp, 0)->isp_topo == TOPO_FL_PORT) { mbreg_t mbs; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_LIP; - if (FCPARAM(isp)->isp_2klogin) { + MBSINIT(&mbs, MBOX_INIT_LIP, MBLOGALL, 0); + if (ISP_CAP_2KLOGIN(isp)) { mbs.ibits = (1 << 10); } - mbs.logval = MBLOGALL; isp_mboxcmd_qnw(isp, &mbs, 1); } if (XS_NOERR(xs)) { @@ -5907,6 +6425,8 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, XS_T *xs, long *rp) { int ru_marked, sv_marked; + int chan = XS_CHANNEL(xs); + switch (sp->req_completion_status) { case RQCS_COMPLETE: if (XS_NOERR(xs)) { @@ -5926,9 +6446,9 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, case RQCS_RESET_OCCURRED: isp_prt(isp, ISP_LOGWARN, - "bus reset destroyed command for %d.%d.%d", + "reset destroyed command for %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); - isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + FCPARAM(isp, chan)->sendmarker = 1; if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BUSRESET); } @@ -5937,7 +6457,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, case RQCS_ABORTED: isp_prt(isp, ISP_LOGERR, "command aborted for %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); - isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + FCPARAM(isp, chan)->sendmarker = 1; if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_ABORTED); } @@ -5952,7 +6472,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, return; case RQCS_DATA_OVERRUN: - XS_RESID(xs) = sp->req_resid; + XS_SET_RESID(xs, sp->req_resid); isp_prt(isp, ISP_LOGERR, "data overrun for command on %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); @@ -5962,8 +6482,9 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, return; case RQCS_24XX_DRE: /* data reassembly error */ - isp_prt(isp, ISP_LOGERR, "data reassembly error for target %d", - XS_TGT(xs)); + isp_prt(isp, ISP_LOGERR, + "Chan %d data reassembly error for target %d", + chan, XS_TGT(xs)); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_ABORTED); } @@ -5971,8 +6492,8 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, return; case RQCS_24XX_TABORT: /* aborted by target */ - isp_prt(isp, ISP_LOGERR, "target %d sent ABTS", - XS_TGT(xs)); + isp_prt(isp, ISP_LOGERR, "Chan %d target %d sent ABTS", + chan, XS_TGT(xs)); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_ABORTED); } @@ -5981,7 +6502,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, case RQCS_DATA_UNDERRUN: ru_marked = (sp->req_scsi_status & RQCS_RU) != 0; /* - * We can get an underrun w/o things being marked + * We can get an underrun w/o things being marked * if we got a non-zero status. */ sv_marked = (sp->req_scsi_status & (RQCS_SV|RQCS_RV)) != 0; @@ -5995,7 +6516,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, } return; } - XS_RESID(xs) = sp->req_resid; + XS_SET_RESID(xs, sp->req_resid); isp_prt(isp, ISP_LOGDEBUG0, "%d.%d.%d data underrun (%d) for command 0x%x", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), @@ -6023,25 +6544,12 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, reason = "logout"; } - isp_prt(isp, ISP_LOGINFO, "port %s for target %d", - reason, XS_TGT(xs)); + isp_prt(isp, ISP_LOGINFO, "Chan %d port %s for target %d", + chan, reason, XS_TGT(xs)); /* - * If we're on a local loop, force a LIP (which is overkill) - * to force a re-login of this unit. If we're on fabric, - * then we'll have to log in again as a matter of course. + * There is no MBOX_INIT_LIP for the 24XX. */ - if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || - FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { - mbreg_t mbs; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_INIT_LIP; - if (FCPARAM(isp)->isp_2klogin) { - mbs.ibits = (1 << 10); - } - mbs.logval = MBLOGALL; - isp_mboxcmd_qnw(isp, &mbs, 1); - } if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } @@ -6049,7 +6557,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, } case RQCS_PORT_CHANGED: isp_prt(isp, ISP_LOGWARN, - "port changed for target %d", XS_TGT(xs)); + "port changed for target %d chan %d", XS_TGT(xs), chan); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } @@ -6058,7 +6566,8 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, case RQCS_24XX_ENOMEM: /* f/w resource unavailable */ isp_prt(isp, ISP_LOGWARN, - "f/w resource unavailable for target %d", XS_TGT(xs)); + "f/w resource unavailable for target %d chan %d", + XS_TGT(xs), chan); if (XS_NOERR(xs)) { *XS_STSP(xs) = SCSI_BUSY; XS_SETERR(xs, HBA_TGTBSY); @@ -6067,8 +6576,8 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, case RQCS_24XX_TMO: /* task management overrun */ isp_prt(isp, ISP_LOGWARN, - "command for target %d overlapped task management", - XS_TGT(xs)); + "command for target %d overlapped task management for " + "chan %d", XS_TGT(xs), chan); if (XS_NOERR(xs)) { *XS_STSP(xs) = SCSI_BUSY; XS_SETERR(xs, HBA_TGTBSY); @@ -6076,8 +6585,9 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, return; default: - isp_prt(isp, ISP_LOGERR, "Unknown Completion Status 0x%x", - sp->req_completion_status); + isp_prt(isp, ISP_LOGERR, + "Unknown Completion Status 0x%x on chan %d", + sp->req_completion_status, chan); break; } if (XS_NOERR(xs)) { @@ -6095,7 +6605,7 @@ isp_fastpost_complete(ispsoftc_t *isp, uint16_t fph) } xs = isp_find_xs(isp, fph); if (xs == NULL) { - isp_prt(isp, ISP_LOGDEBUG1, + isp_prt(isp, ISP_LOGWARN, "Command for fast post handle 0x%x not found", fph); return; } @@ -6106,14 +6616,14 @@ isp_fastpost_complete(ispsoftc_t *isp, uint16_t fph) * we must believe that SCSI status is zero and * that all data transferred. */ - XS_SET_STATE_STAT(isp, xs, NULL); - XS_RESID(xs) = 0; + XS_SET_RESID(xs, 0); *XS_STSP(xs) = SCSI_GOOD; if (XS_XFRLEN(xs)) { ISP_DMAFREE(isp, xs, fph); } - if (isp->isp_nactive) + if (isp->isp_nactive) { isp->isp_nactive--; + } isp->isp_fphccmplt++; isp_done(xs); } @@ -6152,7 +6662,7 @@ isp_mbox_continue(ispsoftc_t *isp) /* * Continue with next word. */ - MEMZERO(&mbs, sizeof (mbs)); + ISP_MEMZERO(&mbs, sizeof (mbs)); ptr = isp->isp_mbxworkp; switch (isp->isp_lastmbxcmd) { case MBOX_WRITE_RAM_WORD: @@ -6397,7 +6907,7 @@ static const uint32_t mbpfc[] = { ISPOPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ ISPOPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ ISPOPMAP(0xff, 0xff), /* 0x06: MBOX_MAILBOX_REG_TEST */ - ISPOPMAP(0x03, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ + ISPOPMAP(0x07, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ ISPOPMAP(0x01, 0x4f), /* 0x08: MBOX_ABOUT_FIRMWARE */ ISPOPMAP(0xdf, 0x01), /* 0x09: MBOX_LOAD_RISC_RAM_2100 */ ISPOPMAP(0xdf, 0x01), /* 0x0a: DUMP RAM */ @@ -6462,9 +6972,9 @@ static const uint32_t mbpfc[] = { ISPOPMAP(0x00, 0x00), /* 0x45: */ ISPOPMAP(0x00, 0x00), /* 0x46: */ ISPOPMAP(0xcf, 0x03), /* 0x47: GET PORT_DATABASE ENHANCED */ - ISPOPMAP(0x00, 0x00), /* 0x48: */ - ISPOPMAP(0x00, 0x00), /* 0x49: */ - ISPOPMAP(0x00, 0x00), /* 0x4a: */ + ISPOPMAP(0xcd, 0x01), /* 0x48: MBOX_INIT_FIRMWARE_MULTI_ID */ + ISPOPMAP(0xcd, 0x01), /* 0x49: MBOX_GET_VP_DATABASE */ + ISPOPMAP(0x2cd, 0x01), /* 0x4a: MBOX_GET_VP_DATABASE_ENTRY */ ISPOPMAP(0x00, 0x00), /* 0x4b: */ ISPOPMAP(0x00, 0x00), /* 0x4c: */ ISPOPMAP(0x00, 0x00), /* 0x4d: */ @@ -6521,7 +7031,7 @@ static const uint32_t mbpfc[] = { /* * Footnotes * - * (1): this sets bits 21..16 in mailbox register #8, which we nominally + * (1): this sets bits 21..16 in mailbox register #8, which we nominally * do not access at this time in the core driver. The caller is * responsible for setting this register first (Gross!). The assumption * is that we won't overflow. @@ -6600,9 +7110,9 @@ static const char *fc_mbcmd_names[] = { NULL, NULL, "GET PORT DATABASE ENHANCED", - NULL, - NULL, - NULL, + "INIT FIRMWARE MULTI ID", + "GET VP DATABASE", + "GET VP DATABASE ENTRY", NULL, NULL, NULL, @@ -6697,7 +7207,7 @@ isp_mboxcmd_qnw(ispsoftc_t *isp, mbreg_t *mbp, int nodelay) * command. */ if (nodelay) { - USEC_DELAY(1000); + ISP_DELAY(1000); } } @@ -6748,7 +7258,7 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) for (box = 0; box < MAX_MAILBOX(isp); box++) { if (ibits & (1 << box)) { - isp_prt(isp, ISP_LOGDEBUG1, "IN mbox %d = 0x%04x", box, + isp_prt(isp, ISP_LOGDEBUG3, "IN mbox %d = 0x%04x", box, mbp->param[box]); ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]); } @@ -6781,6 +7291,7 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) * Did the command time out? */ if (mbp->param[0] == MBOX_TIMEOUT) { + isp->isp_mboxbsy = 0; MBOX_RELEASE(isp); goto out; } @@ -6791,21 +7302,21 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) for (box = 0; box < MAX_MAILBOX(isp); box++) { if (obits & (1 << box)) { mbp->param[box] = isp->isp_mboxtmp[box]; - isp_prt(isp, ISP_LOGDEBUG1, "OUT mbox %d = 0x%04x", box, + isp_prt(isp, ISP_LOGDEBUG3, "OUT mbox %d = 0x%04x", box, mbp->param[box]); } } + isp->isp_mboxbsy = 0; MBOX_RELEASE(isp); out: - isp->isp_mboxbsy = 0; if (mbp->logval == 0 || opcode == MBOX_EXEC_FIRMWARE) { return; } cname = (IS_FC(isp))? fc_mbcmd_names[opcode] : scsi_mbcmd_names[opcode]; if (cname == NULL) { cname = tname; - SNPRINTF(tname, sizeof tname, "opcode %x", opcode); + ISP_SNPRINTF(tname, sizeof tname, "opcode %x", opcode); } /* @@ -6862,7 +7373,7 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) xname = "TIMEOUT"; break; default: - SNPRINTF(mname, sizeof mname, "error 0x%x", mbp->param[0]); + ISP_SNPRINTF(mname, sizeof mname, "error 0x%x", mbp->param[0]); xname = mname; break; } @@ -6873,15 +7384,13 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) } static void -isp_fw_state(ispsoftc_t *isp) +isp_fw_state(ispsoftc_t *isp, int chan) { if (IS_FC(isp)) { mbreg_t mbs; - fcparam *fcp = isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_FW_STATE; - mbs.logval = MBLOGALL; + MBSINIT(&mbs, MBOX_GET_FW_STATE, MBLOGALL, 0); isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { fcp->isp_fwstate = mbs.param[1]; @@ -6890,34 +7399,20 @@ isp_fw_state(ispsoftc_t *isp) } static void -isp_update(ispsoftc_t *isp) -{ - int bus, upmask; - - for (bus = 0, upmask = isp->isp_update; upmask != 0; bus++) { - if (upmask & (1 << bus)) { - isp_update_bus(isp, bus); - } - upmask &= ~(1 << bus); - } -} - -static void -isp_update_bus(ispsoftc_t *isp, int bus) +isp_spi_update(ispsoftc_t *isp, int chan) { int tgt; mbreg_t mbs; sdparam *sdp; - isp->isp_update &= ~(1 << bus); if (IS_FC(isp)) { /* * There are no 'per-bus' settings for Fibre Channel. */ return; } - sdp = isp->isp_param; - sdp += bus; + sdp = SDPARAM(isp, chan); + sdp->update = 0; for (tgt = 0; tgt < MAX_TARGETS; tgt++) { uint16_t flags, period, offset; @@ -6927,7 +7422,7 @@ isp_update_bus(ispsoftc_t *isp, int bus) sdp->isp_devparam[tgt].dev_update = 0; sdp->isp_devparam[tgt].dev_refresh = 0; isp_prt(isp, ISP_LOGDEBUG0, - "skipping target %d bus %d update", tgt, bus); + "skipping target %d bus %d update", tgt, chan); continue; } /* @@ -6937,7 +7432,7 @@ isp_update_bus(ispsoftc_t *isp, int bus) * current device state, get the current parameters. */ - MEMZERO(&mbs, sizeof (mbs)); + MBSINIT(&mbs, 0, MBLOGALL, 0); /* * Refresh overrides set @@ -6985,20 +7480,19 @@ isp_update_bus(ispsoftc_t *isp, int bus) (sdp->isp_devparam[tgt].goal_flags & DPARM_TQING); isp_prt(isp, ISP_LOGDEBUG0, "bus %d set tgt %d flags 0x%x off 0x%x period 0x%x", - bus, tgt, mbs.param[2], mbs.param[3] >> 8, + chan, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); get = 0; } else { continue; } - mbs.param[1] = (bus << 15) | (tgt << 8); - mbs.logval = MBLOGALL; + mbs.param[1] = (chan << 15) | (tgt << 8); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { continue; } if (get == 0) { - isp->isp_sendmarker |= (1 << bus); + sdp->sendmarker = 1; sdp->isp_devparam[tgt].dev_update = 0; sdp->isp_devparam[tgt].dev_refresh = 1; } else { @@ -7009,48 +7503,41 @@ isp_update_bus(ispsoftc_t *isp, int bus) sdp->isp_devparam[tgt].actv_flags = flags; sdp->isp_devparam[tgt].actv_period = period; sdp->isp_devparam[tgt].actv_offset = offset; - get = (bus << 16) | tgt; - (void) isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, &get); + isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, chan, tgt); } } for (tgt = 0; tgt < MAX_TARGETS; tgt++) { if (sdp->isp_devparam[tgt].dev_update || sdp->isp_devparam[tgt].dev_refresh) { - isp->isp_update |= (1 << bus); + sdp->update = 1; break; } } } -#ifndef DEFAULT_EXEC_THROTTLE -#define DEFAULT_EXEC_THROTTLE(isp) ISP_EXEC_THROTTLE -#endif - static void -isp_setdfltparm(ispsoftc_t *isp, int channel) +isp_setdfltsdparm(ispsoftc_t *isp) { int tgt; - sdparam *sdp; + sdparam *sdp, *sdp1; - sdp = (sdparam *) isp->isp_param; - sdp += channel; - - /* - * Been there, done that, got the T-shirt... - */ - if (sdp->isp_gotdparms) { - return; + sdp = SDPARAM(isp, 0); + sdp->role = GET_DEFAULT_ROLE(isp, 0); + if (IS_DUALBUS(isp)) { + sdp1 = sdp + 1; + sdp1->role = GET_DEFAULT_ROLE(isp, 1); + } else { + sdp1 = NULL; } - sdp->isp_gotdparms = 1; - sdp->isp_bad_nvram = 0; + /* * Establish some default parameters. */ sdp->isp_cmd_dma_burst_enable = 0; sdp->isp_data_dma_burst_enabl = 1; sdp->isp_fifo_threshold = 0; - sdp->isp_initiator_id = DEFAULT_IID(isp); + sdp->isp_initiator_id = DEFAULT_IID(isp, 0); if (isp->isp_type >= ISP_HA_SCSI_1040) { sdp->isp_async_data_setup = 9; } else { @@ -7072,50 +7559,6 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) sdp->isp_devparam[tgt].dev_enable = 1; } - /* - * If we've not been told to avoid reading NVRAM, try and read it. - * If we're successful reading it, we can then return because NVRAM - * will tell us what the desired settings are. Otherwise, we establish - * some reasonable 'fake' nvram and goal defaults. - */ - - if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { - if (isp_read_nvram(isp) == 0) { - return; - } - sdp->isp_bad_nvram = 1; - } - - /* - * Now try and see whether we have specific values for them. - */ - if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { - mbreg_t mbs; - - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_ACT_NEG_STATE; - mbs.logval = MBLOGNONE; - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - sdp->isp_req_ack_active_neg = 1; - sdp->isp_data_line_active_neg = 1; - } else { - sdp->isp_req_ack_active_neg = - (mbs.param[1+channel] >> 4) & 0x1; - sdp->isp_data_line_active_neg = - (mbs.param[1+channel] >> 5) & 0x1; - } - } - - isp_prt(isp, ISP_LOGDEBUG0, sc0, sc3, - 0, sdp->isp_fifo_threshold, sdp->isp_initiator_id, - sdp->isp_bus_reset_delay, sdp->isp_retry_count, - sdp->isp_retry_delay, sdp->isp_async_data_setup); - isp_prt(isp, ISP_LOGDEBUG0, sc1, sc3, - sdp->isp_req_ack_active_neg, sdp->isp_data_line_active_neg, - sdp->isp_data_dma_burst_enabl, sdp->isp_cmd_dma_burst_enable, - sdp->isp_selection_timeout, sdp->isp_max_queue_depth); - /* * The trick here is to establish a default for the default (honk!) * state (goal_flags). Then try and get the current status from @@ -7161,49 +7604,97 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) sdp->isp_devparam[tgt].goal_period = sdp->isp_devparam[tgt].nvrm_period = per; - isp_prt(isp, ISP_LOGDEBUG0, sc2, sc3, - channel, tgt, sdp->isp_devparam[tgt].nvrm_flags, - sdp->isp_devparam[tgt].nvrm_offset, - sdp->isp_devparam[tgt].nvrm_period); - } -} - -#ifndef DEFAULT_FRAMESIZE -#define DEFAULT_FRAMESIZE(isp) ICB_DFLT_FRMLEN -#endif -static void -isp_setdfltfcparm(ispsoftc_t *isp) -{ - fcparam *fcp = FCPARAM(isp); - - if (fcp->isp_gotdparms) { - return; - } - fcp->isp_gotdparms = 1; - fcp->isp_bad_nvram = 0; - fcp->isp_maxfrmlen = DEFAULT_FRAMESIZE(isp); - fcp->isp_maxalloc = ICB_DFLT_ALLOC; - fcp->isp_execthrottle = DEFAULT_EXEC_THROTTLE(isp); - fcp->isp_retry_delay = ICB_DFLT_RDELAY; - fcp->isp_retry_count = ICB_DFLT_RCOUNT; - /* Platform specific.... */ - fcp->isp_loopid = DEFAULT_LOOPID(isp); - fcp->isp_wwnn_nvram = DEFAULT_NODEWWN(isp); - fcp->isp_wwpn_nvram = DEFAULT_PORTWWN(isp); - fcp->isp_fwoptions = 0; - fcp->isp_fwoptions |= ICBOPT_FAIRNESS; - fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; - fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS; - fcp->isp_fwoptions |= ICBOPT_FAST_POST; - if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { - fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX; } /* - * Make sure this is turned off now until we get - * extended options from NVRAM + * If we're a dual bus card, just copy the data over */ - fcp->isp_fwoptions &= ~ICBOPT_EXTENDED; + if (sdp1) { + *sdp1 = *sdp; + sdp1->isp_initiator_id = DEFAULT_IID(isp, 1); + } + + /* + * If we've not been told to avoid reading NVRAM, try and read it. + * If we're successful reading it, we can then return because NVRAM + * will tell us what the desired settings are. Otherwise, we establish + * some reasonable 'fake' nvram and goal defaults. + */ + if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { + mbreg_t mbs; + + if (isp_read_nvram(isp, 0) == 0) { + if (IS_DUALBUS(isp)) { + if (isp_read_nvram(isp, 1) == 0) { + return; + } + } + } + MBSINIT(&mbs, MBOX_GET_ACT_NEG_STATE, MBLOGNONE, 0); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + sdp->isp_req_ack_active_neg = 1; + sdp->isp_data_line_active_neg = 1; + if (sdp1) { + sdp1->isp_req_ack_active_neg = 1; + sdp1->isp_data_line_active_neg = 1; + } + } else { + sdp->isp_req_ack_active_neg = + (mbs.param[1] >> 4) & 0x1; + sdp->isp_data_line_active_neg = + (mbs.param[1] >> 5) & 0x1; + if (sdp1) { + sdp1->isp_req_ack_active_neg = + (mbs.param[2] >> 4) & 0x1; + sdp1->isp_data_line_active_neg = + (mbs.param[2] >> 5) & 0x1; + } + } + } + +} + +static void +isp_setdfltfcparm(ispsoftc_t *isp, int chan) +{ + fcparam *fcp = FCPARAM(isp, chan); + + /* + * Establish some default parameters. + */ + fcp->role = GET_DEFAULT_ROLE(isp, chan); + fcp->isp_maxalloc = ICB_DFLT_ALLOC; + fcp->isp_retry_delay = ICB_DFLT_RDELAY; + fcp->isp_retry_count = ICB_DFLT_RCOUNT; + fcp->isp_loopid = DEFAULT_LOOPID(isp, chan); + fcp->isp_wwnn_nvram = DEFAULT_NODEWWN(isp, chan); + fcp->isp_wwpn_nvram = DEFAULT_PORTWWN(isp, chan); + fcp->isp_fwoptions = 0; + fcp->isp_lasthdl = NIL_HANDLE; + + if (IS_24XX(isp)) { + fcp->isp_fwoptions |= ICB2400_OPT1_FAIRNESS; + fcp->isp_fwoptions |= ICB2400_OPT1_HARD_ADDRESS; + if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { + fcp->isp_fwoptions |= ICB2400_OPT1_FULL_DUPLEX; + } + fcp->isp_fwoptions |= ICB2400_OPT1_BOTH_WWNS; + } else { + fcp->isp_fwoptions |= ICBOPT_FAIRNESS; + fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; + fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS; + fcp->isp_fwoptions |= ICBOPT_FAST_POST; + if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { + fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX; + } + /* + * Make sure this is turned off now until we get + * extended options from NVRAM + */ + fcp->isp_fwoptions &= ~ICBOPT_EXTENDED; + } + /* * Now try and read NVRAM unless told to not do so. @@ -7215,61 +7706,22 @@ isp_setdfltfcparm(ispsoftc_t *isp) * Give a couple of tries at reading NVRAM. */ for (i = 0; i < 2; i++) { - j = isp_read_nvram(isp); + j = isp_read_nvram(isp, chan); if (j == 0) { break; } } if (j) { - fcp->isp_bad_nvram = 1; isp->isp_confopts |= ISP_CFG_NONVRAM; - isp->isp_confopts |= ISP_CFG_OWNWWPN; - isp->isp_confopts |= ISP_CFG_OWNWWNN; } - } else { - isp->isp_confopts |= ISP_CFG_OWNWWPN|ISP_CFG_OWNWWNN; } - /* - * Set node && port to override platform set defaults - * unless the nvram read failed (or none was done), - * or the platform code wants to use what had been - * set in the defaults. - */ - if (isp->isp_confopts & ISP_CFG_OWNWWNN) { - isp_prt(isp, ISP_LOGCONFIG, "Using Node WWN 0x%08x%08x", - (uint32_t) (DEFAULT_NODEWWN(isp) >> 32), - (uint32_t) (DEFAULT_NODEWWN(isp) & 0xffffffff)); - ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp); - } else { - /* - * We always start out with values derived - * from NVRAM or our platform default. - */ - ISP_NODEWWN(isp) = fcp->isp_wwnn_nvram; - if (fcp->isp_wwnn_nvram == 0) { - isp_prt(isp, ISP_LOGCONFIG, - "bad WWNN- using default"); - ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp); - } - } - if (isp->isp_confopts & ISP_CFG_OWNWWPN) { - isp_prt(isp, ISP_LOGCONFIG, "Using Port WWN 0x%08x%08x", - (uint32_t) (DEFAULT_PORTWWN(isp) >> 32), - (uint32_t) (DEFAULT_PORTWWN(isp) & 0xffffffff)); - ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp); - } else { - /* - * We always start out with values derived - * from NVRAM or our platform default. - */ - ISP_PORTWWN(isp) = fcp->isp_wwpn_nvram; - if (fcp->isp_wwpn_nvram == 0) { - isp_prt(isp, ISP_LOGCONFIG, - "bad WWPN- using default"); - ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp); - } - } + fcp->isp_wwnn = ACTIVE_NODEWWN(isp, chan); + fcp->isp_wwpn = ACTIVE_PORTWWN(isp, chan); + isp_prt(isp, ISP_LOGCONFIG, "Chan %d 0x%08x%08x/0x%08x%08x Role %s", + chan, (uint32_t) (fcp->isp_wwnn >> 32), (uint32_t) (fcp->isp_wwnn), + (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) (fcp->isp_wwpn), + isp_class3_roles[fcp->role]); } /* @@ -7279,28 +7731,28 @@ isp_setdfltfcparm(ispsoftc_t *isp) */ void -isp_reinit(ispsoftc_t *isp) +isp_reinit(ispsoftc_t *isp, int do_load_defaults) { - XS_T *xs; - uint32_t tmp; + int i; + + isp_reset(isp, do_load_defaults); - if (IS_FC(isp)) { - ISP_MARK_PORTDB(isp, 0); - } - isp_reset(isp); if (isp->isp_state != ISP_RESETSTATE) { - isp_prt(isp, ISP_LOGERR, "isp_reinit cannot reset card"); - } else if (isp->isp_role != ISP_ROLE_NONE) { - isp_init(isp); - if (isp->isp_state == ISP_INITSTATE) { - isp->isp_state = ISP_RUNSTATE; - } - if (isp->isp_state != ISP_RUNSTATE) { - isp_prt(isp, ISP_LOGERR, - "isp_reinit cannot restart card"); - ISP_DISABLE_INTS(isp); - } - } else { + isp_prt(isp, ISP_LOGERR, "%s: cannot reset card", __func__); + ISP_DISABLE_INTS(isp); + goto cleanup; + } + + isp_init(isp); + + if (isp->isp_state == ISP_INITSTATE) { + isp->isp_state = ISP_RUNSTATE; + } + + if (isp->isp_state != ISP_RUNSTATE) { +#ifndef ISP_TARGET_MODE + isp_prt(isp, ISP_LOGWARN, "%s: not at runstate", __func__); +#endif ISP_DISABLE_INTS(isp); if (IS_FC(isp)) { /* @@ -7315,51 +7767,36 @@ isp_reinit(ispsoftc_t *isp) } } } + + cleanup: + isp->isp_nactive = 0; - for (tmp = 0; tmp < isp->isp_maxcmds; tmp++) { - uint32_t handle; - - xs = isp->isp_xflist[tmp]; - if (xs == NULL) { - continue; + isp_clear_commands(isp); + if (IS_FC(isp)) { + for (i = 0; i < isp->isp_nchan; i++) { + ISP_MARK_PORTDB(isp, i, -1); } - handle = isp_find_handle(isp, xs); - if (handle == 0) { - continue; - } - isp_destroy_handle(isp, handle); - if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, handle); - XS_RESID(xs) = XS_XFRLEN(xs); - } else { - XS_RESID(xs) = 0; - } - XS_SETERR(xs, HBA_BUSRESET); - isp_done(xs); } -#ifdef ISP_TARGET_MODE - MEMZERO(isp->isp_tgtlist, isp->isp_maxcmds * sizeof (void **)); -#endif } /* * NVRAM Routines */ static int -isp_read_nvram(ispsoftc_t *isp) +isp_read_nvram(ispsoftc_t *isp, int bus) { int i, amt, retval; uint8_t csum, minversion; union { - uint8_t _x[ISP2100_NVRAM_SIZE]; - uint16_t _s[ISP2100_NVRAM_SIZE>>1]; + uint8_t _x[ISP2400_NVRAM_SIZE]; + uint16_t _s[ISP2400_NVRAM_SIZE>>1]; } _n; #define nvram_data _n._x #define nvram_words _n._s if (IS_24XX(isp)) { - return (isp_read_nvram_2400(isp)); + return (isp_read_nvram_2400(isp, nvram_data)); } else if (IS_FC(isp)) { amt = ISP2100_NVRAM_SIZE; minversion = 1; @@ -7403,14 +7840,11 @@ isp_read_nvram(ispsoftc_t *isp) } if (IS_ULTRA3(isp)) { - isp_parse_nvram_12160(isp, 0, nvram_data); - if (IS_12160(isp)) - isp_parse_nvram_12160(isp, 1, nvram_data); + isp_parse_nvram_12160(isp, bus, nvram_data); } else if (IS_1080(isp)) { - isp_parse_nvram_1080(isp, 0, nvram_data); + isp_parse_nvram_1080(isp, bus, nvram_data); } else if (IS_1280(isp) || IS_1240(isp)) { - isp_parse_nvram_1080(isp, 0, nvram_data); - isp_parse_nvram_1080(isp, 1, nvram_data); + isp_parse_nvram_1080(isp, bus, nvram_data); } else if (IS_SCSI(isp)) { isp_parse_nvram_1020(isp, nvram_data); } else { @@ -7424,18 +7858,17 @@ isp_read_nvram(ispsoftc_t *isp) } static int -isp_read_nvram_2400(ispsoftc_t *isp) +isp_read_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) { - uint8_t *nvram_data = FCPARAM(isp)->isp_scratch; int retval = 0; uint32_t addr, csum, lwrds, *dptr; - + if (isp->isp_port) { addr = ISP2400_NVRAM_PORT1_ADDR; } else { addr = ISP2400_NVRAM_PORT0_ADDR; } - + dptr = (uint32_t *) nvram_data; for (lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { isp_rd_2400_nvram(isp, addr++, dptr++); @@ -7470,12 +7903,12 @@ isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) uint16_t bit, rqst, junk; ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT); - USEC_DELAY(10); + ISP_DELAY(10); ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK); - USEC_DELAY(10); + ISP_DELAY(10); if (IS_FC(isp)) { - wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1); + wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1); if (IS_2312(isp) && isp->isp_port) { wo += 128; } @@ -7501,13 +7934,13 @@ isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) bit = BIU_NVRAM_SELECT; } ISP_WRITE(isp, BIU_NVRAM, bit); - USEC_DELAY(10); + ISP_DELAY(10); junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ ISP_WRITE(isp, BIU_NVRAM, bit | BIU_NVRAM_CLOCK); - USEC_DELAY(10); + ISP_DELAY(10); junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ ISP_WRITE(isp, BIU_NVRAM, bit); - USEC_DELAY(10); + ISP_DELAY(10); junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ } /* @@ -7518,18 +7951,18 @@ isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) uint16_t rv; *rp <<= 1; ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK); - USEC_DELAY(10); + ISP_DELAY(10); rv = ISP_READ(isp, BIU_NVRAM); if (rv & BIU_NVRAM_DATAIN) { *rp |= 1; } - USEC_DELAY(10); + ISP_DELAY(10); ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT); - USEC_DELAY(10); + ISP_DELAY(10); junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ } ISP_WRITE(isp, BIU_NVRAM, 0); - USEC_DELAY(10); + ISP_DELAY(10); junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ ISP_SWIZZLE_NVRAM_WORD(isp, rp); } @@ -7538,12 +7971,15 @@ static void isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) { int loops = 0; - const uint32_t base = 0x7ffe0000; + uint32_t base = 0x7ffe0000; uint32_t tmp = 0; + if (IS_25XX(isp)) { + base = 0x7ff00000 | 0x48000; + } ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr); for (loops = 0; loops < 5000; loops++) { - USEC_DELAY(10); + ISP_DELAY(10); tmp = ISP_READ(isp, BIU2400_FLASH_ADDR); if ((tmp & (1U << 31)) != 0) { break; @@ -7560,7 +7996,7 @@ isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) static void isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) { - sdparam *sdp = (sdparam *) isp->isp_param; + sdparam *sdp = SDPARAM(isp, 0); int tgt; sdp->isp_fifo_threshold = @@ -7616,15 +8052,6 @@ isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) sdp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data); - isp_prt(isp, ISP_LOGDEBUG0, sc0, sc4, - 0, sdp->isp_fifo_threshold, sdp->isp_initiator_id, - sdp->isp_bus_reset_delay, sdp->isp_retry_count, - sdp->isp_retry_delay, sdp->isp_async_data_setup); - isp_prt(isp, ISP_LOGDEBUG0, sc1, sc4, - sdp->isp_req_ack_active_neg, sdp->isp_data_line_active_neg, - sdp->isp_data_dma_burst_enabl, sdp->isp_cmd_dma_burst_enable, - sdp->isp_selection_timeout, sdp->isp_max_queue_depth); - for (tgt = 0; tgt < MAX_TARGETS; tgt++) { sdp->isp_devparam[tgt].dev_enable = ISP_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt); @@ -7670,10 +8097,6 @@ isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) if (ISP_NVRAM_TGT_DISC(nvram_data, tgt)) sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; sdp->isp_devparam[tgt].actv_flags = 0; /* we don't know */ - isp_prt(isp, ISP_LOGDEBUG0, sc2, sc4, - 0, tgt, sdp->isp_devparam[tgt].nvrm_flags, - sdp->isp_devparam[tgt].nvrm_offset, - sdp->isp_devparam[tgt].nvrm_period); sdp->isp_devparam[tgt].goal_offset = sdp->isp_devparam[tgt].nvrm_offset; sdp->isp_devparam[tgt].goal_period = @@ -7686,11 +8109,9 @@ isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) static void isp_parse_nvram_1080(ispsoftc_t *isp, int bus, uint8_t *nvram_data) { - sdparam *sdp = (sdparam *) isp->isp_param; + sdparam *sdp = SDPARAM(isp, bus); int tgt; - sdp += bus; - sdp->isp_fifo_threshold = ISP1080_NVRAM_FIFO_THRESHOLD(nvram_data); @@ -7728,16 +8149,6 @@ isp_parse_nvram_1080(ispsoftc_t *isp, int bus, uint8_t *nvram_data) sdp->isp_max_queue_depth = ISP1080_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus); - isp_prt(isp, ISP_LOGDEBUG0, sc0, sc4, - bus, sdp->isp_fifo_threshold, sdp->isp_initiator_id, - sdp->isp_bus_reset_delay, sdp->isp_retry_count, - sdp->isp_retry_delay, sdp->isp_async_data_setup); - isp_prt(isp, ISP_LOGDEBUG0, sc1, sc4, - sdp->isp_req_ack_active_neg, sdp->isp_data_line_active_neg, - sdp->isp_data_dma_burst_enabl, sdp->isp_cmd_dma_burst_enable, - sdp->isp_selection_timeout, sdp->isp_max_queue_depth); - - for (tgt = 0; tgt < MAX_TARGETS; tgt++) { sdp->isp_devparam[tgt].dev_enable = ISP1080_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt, bus); @@ -7762,10 +8173,6 @@ isp_parse_nvram_1080(ispsoftc_t *isp, int bus, uint8_t *nvram_data) if (ISP1080_NVRAM_TGT_DISC(nvram_data, tgt, bus)) sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; sdp->isp_devparam[tgt].actv_flags = 0; - isp_prt(isp, ISP_LOGDEBUG0, sc2, sc4, - bus, tgt, sdp->isp_devparam[tgt].nvrm_flags, - sdp->isp_devparam[tgt].nvrm_offset, - sdp->isp_devparam[tgt].nvrm_period); sdp->isp_devparam[tgt].goal_offset = sdp->isp_devparam[tgt].nvrm_offset; sdp->isp_devparam[tgt].goal_period = @@ -7778,11 +8185,9 @@ isp_parse_nvram_1080(ispsoftc_t *isp, int bus, uint8_t *nvram_data) static void isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) { - sdparam *sdp = (sdparam *) isp->isp_param; + sdparam *sdp = SDPARAM(isp, bus); int tgt; - sdp += bus; - sdp->isp_fifo_threshold = ISP12160_NVRAM_FIFO_THRESHOLD(nvram_data); @@ -7820,15 +8225,6 @@ isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) sdp->isp_max_queue_depth = ISP12160_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus); - isp_prt(isp, ISP_LOGDEBUG0, sc0, sc4, - bus, sdp->isp_fifo_threshold, sdp->isp_initiator_id, - sdp->isp_bus_reset_delay, sdp->isp_retry_count, - sdp->isp_retry_delay, sdp->isp_async_data_setup); - isp_prt(isp, ISP_LOGDEBUG0, sc1, sc4, - sdp->isp_req_ack_active_neg, sdp->isp_data_line_active_neg, - sdp->isp_data_dma_burst_enabl, sdp->isp_cmd_dma_burst_enable, - sdp->isp_selection_timeout, sdp->isp_max_queue_depth); - for (tgt = 0; tgt < MAX_TARGETS; tgt++) { sdp->isp_devparam[tgt].dev_enable = ISP12160_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt, bus); @@ -7853,10 +8249,6 @@ isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) if (ISP12160_NVRAM_TGT_DISC(nvram_data, tgt, bus)) sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; sdp->isp_devparam[tgt].actv_flags = 0; - isp_prt(isp, ISP_LOGDEBUG0, sc2, sc4, - bus, tgt, sdp->isp_devparam[tgt].nvrm_flags, - sdp->isp_devparam[tgt].nvrm_offset, - sdp->isp_devparam[tgt].nvrm_period); sdp->isp_devparam[tgt].goal_offset = sdp->isp_devparam[tgt].nvrm_offset; sdp->isp_devparam[tgt].goal_period = @@ -7866,42 +8258,10 @@ isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) } } -static void -isp_fix_nvram_wwns(ispsoftc_t *isp) -{ - fcparam *fcp = FCPARAM(isp); - - /* - * Make sure we have both Node and Port as non-zero values. - */ - if (fcp->isp_wwnn_nvram != 0 && fcp->isp_wwpn_nvram == 0) { - fcp->isp_wwpn_nvram = fcp->isp_wwnn_nvram; - } else if (fcp->isp_wwnn_nvram == 0 && fcp->isp_wwpn_nvram != 0) { - fcp->isp_wwnn_nvram = fcp->isp_wwpn_nvram; - } - - /* - * Make the Node and Port values sane if they're NAA == 2. - * This means to clear bits 48..56 for the Node WWN and - * make sure that there's some non-zero value in 48..56 - * for the Port WWN. - */ - if (fcp->isp_wwnn_nvram && fcp->isp_wwpn_nvram) { - if ((fcp->isp_wwnn_nvram & (((uint64_t) 0xfff) << 48)) != 0 && - (fcp->isp_wwnn_nvram >> 60) == 2) { - fcp->isp_wwnn_nvram &= ~((uint64_t) 0xfff << 48); - } - if ((fcp->isp_wwpn_nvram & (((uint64_t) 0xfff) << 48)) == 0 && - (fcp->isp_wwpn_nvram >> 60) == 2) { - fcp->isp_wwpn_nvram |= ((uint64_t) 1 << 56); - } - } -} - static void isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) { - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, 0); uint64_t wwn; /* @@ -7918,7 +8278,7 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) wwn = ISP2100_NVRAM_PORT_NAME(nvram_data); if (wwn) { isp_prt(isp, ISP_LOGCONFIG, "NVRAM Port WWN 0x%08x%08x", - (uint32_t) (wwn >> 32), (uint32_t) (wwn & 0xffffffff)); + (uint32_t) (wwn >> 32), (uint32_t) (wwn)); if ((wwn >> 60) == 0) { wwn |= (((uint64_t) 2)<< 60); } @@ -7929,7 +8289,7 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) if (wwn) { isp_prt(isp, ISP_LOGCONFIG, "NVRAM Node WWN 0x%08x%08x", (uint32_t) (wwn >> 32), - (uint32_t) (wwn & 0xffffffff)); + (uint32_t) (wwn)); if ((wwn >> 60) == 0) { wwn |= (((uint64_t) 2)<< 60); } @@ -7939,11 +8299,10 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) } fcp->isp_wwnn_nvram = wwn; - isp_fix_nvram_wwns(isp); - fcp->isp_maxalloc = ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data); if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { - fcp->isp_maxfrmlen = ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data); + DEFAULT_FRAMESIZE(isp) = + ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data); } fcp->isp_retry_delay = ISP2100_NVRAM_RETRY_DELAY(nvram_data); fcp->isp_retry_count = ISP2100_NVRAM_RETRY_COUNT(nvram_data); @@ -7951,14 +8310,16 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) fcp->isp_loopid = ISP2100_NVRAM_HARDLOOPID(nvram_data); } if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { - fcp->isp_execthrottle = + DEFAULT_EXEC_THROTTLE(isp) = ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data); } fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data); isp_prt(isp, ISP_LOGDEBUG0, "NVRAM 0x%08x%08x 0x%08x%08x maxalloc %d maxframelen %d", - (uint32_t) (fcp->isp_wwnn_nvram >> 32), (uint32_t) fcp->isp_wwnn_nvram, - (uint32_t) (fcp->isp_wwpn_nvram >> 32), (uint32_t) fcp->isp_wwpn_nvram, + (uint32_t) (fcp->isp_wwnn_nvram >> 32), + (uint32_t) fcp->isp_wwnn_nvram, + (uint32_t) (fcp->isp_wwpn_nvram >> 32), + (uint32_t) fcp->isp_wwpn_nvram, ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data), ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data)); isp_prt(isp, ISP_LOGDEBUG0, @@ -7977,7 +8338,7 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) static void isp_parse_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) { - fcparam *fcp = FCPARAM(isp); + fcparam *fcp = FCPARAM(isp, 0); uint64_t wwn; isp_prt(isp, ISP_LOGDEBUG0, @@ -8012,343 +8373,21 @@ isp_parse_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) } fcp->isp_wwnn_nvram = wwn; - isp_fix_nvram_wwns(isp); - if (ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data)) { fcp->isp_maxalloc = ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data); } if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { - fcp->isp_maxfrmlen = ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data); + DEFAULT_FRAMESIZE(isp) = + ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data); } if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { fcp->isp_loopid = ISP2400_NVRAM_HARDLOOPID(nvram_data); } if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { - fcp->isp_execthrottle = + DEFAULT_EXEC_THROTTLE(isp) = ISP2400_NVRAM_EXECUTION_THROTTLE(nvram_data); } fcp->isp_fwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS1(nvram_data); fcp->isp_xfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data); fcp->isp_zfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data); } - -#ifdef ISP_FW_CRASH_DUMP -static void isp2200_fw_dump(ispsoftc_t *); -static void isp2300_fw_dump(ispsoftc_t *); - -static void -isp2200_fw_dump(ispsoftc_t *isp) -{ - int i, j; - mbreg_t mbs; - uint16_t *ptr; - - MEMZERO(&mbs, sizeof (mbs)); - ptr = FCPARAM(isp)->isp_dump_data; - if (ptr == NULL) { - isp_prt(isp, ISP_LOGERR, - "No place to dump RISC registers and SRAM"); - return; - } - if (*ptr++) { - isp_prt(isp, ISP_LOGERR, - "dump area for RISC registers and SRAM already used"); - return; - } - ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { - break; - } - } - if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { - /* - * PBIU Registers - */ - for (i = 0; i < 8; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + (i << 1)); - } - - /* - * Mailbox Registers - */ - for (i = 0; i < 8; i++) { - *ptr++ = ISP_READ(isp, MBOX_BLOCK + (i << 1)); - } - - /* - * DMA Registers - */ - for (i = 0; i < 48; i++) { - *ptr++ = ISP_READ(isp, DMA_BLOCK + 0x20 + (i << 1)); - } - - /* - * RISC H/W Registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0); - for (i = 0; i < 16; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0xA0 + (i << 1)); - } - - /* - * RISC GP Registers - */ - for (j = 0; j < 8; j++) { - ISP_WRITE(isp, BIU_BLOCK + 0xA4, 0x2000 + (j << 8)); - for (i = 0; i < 16; i++) { - *ptr++ = - ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - } - - /* - * Frame Buffer Hardware Registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x10); - for (i = 0; i < 16; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * Fibre Protocol Module 0 Hardware Registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x20); - for (i = 0; i < 64; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * Fibre Protocol Module 1 Hardware Registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x30); - for (i = 0; i < 64; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - } else { - isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause"); - return; - } - isp_prt(isp, ISP_LOGALL, - "isp_fw_dump: RISC registers dumped successfully"); - ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if (ISP_READ(isp, OUTMAILBOX0) == 0) { - break; - } - } - if (ISP_READ(isp, OUTMAILBOX0) != 0) { - isp_prt(isp, ISP_LOGERR, "Board Would Not Reset"); - return; - } - ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { - break; - } - } - if ((ISP_READ(isp, HCCR) & HCCR_PAUSE) == 0) { - isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause After Reset"); - return; - } - ISP_WRITE(isp, RISC_EMB, 0xf2); - ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if ((ISP_READ(isp, HCCR) & HCCR_PAUSE) == 0) { - break; - } - } - ISP_ENABLE_INTS(isp); - mbs.param[0] = MBOX_READ_RAM_WORD; - mbs.param[1] = 0x1000; - isp->isp_mbxworkp = (void *) ptr; - isp->isp_mbxwrk0 = 0xefff; /* continuation count */ - isp->isp_mbxwrk1 = 0x1001; /* next SRAM address */ - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGWARN, - "RAM DUMP FAILED @ WORD %x", isp->isp_mbxwrk1); - return; - } - ptr = isp->isp_mbxworkp; /* finish fetch of final word */ - *ptr++ = isp->isp_mboxtmp[2]; - isp_prt(isp, ISP_LOGALL, "isp_fw_dump: SRAM dumped successfully"); - FCPARAM(isp)->isp_dump_data[0] = isp->isp_type; /* now used */ - (void) isp_async(isp, ISPASYNC_FW_DUMPED, 0); -} - -static void -isp2300_fw_dump(ispsoftc_t *isp) -{ - int i, j; - mbreg_t mbs; - uint16_t *ptr; - - MEMZERO(&mbs, sizeof (mbs)); - ptr = FCPARAM(isp)->isp_dump_data; - if (ptr == NULL) { - isp_prt(isp, ISP_LOGERR, - "No place to dump RISC registers and SRAM"); - return; - } - if (*ptr++) { - isp_prt(isp, ISP_LOGERR, - "dump area for RISC registers and SRAM already used"); - return; - } - ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { - break; - } - } - if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { - /* - * PBIU registers - */ - for (i = 0; i < 8; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + (i << 1)); - } - - /* - * ReqQ-RspQ-Risc2Host Status registers - */ - for (i = 0; i < 8; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x10 + (i << 1)); - } - - /* - * Mailbox Registers - */ - for (i = 0; i < 32; i++) { - *ptr++ = - ISP_READ(isp, PCI_MBOX_REGS2300_OFF + (i << 1)); - } - - /* - * Auto Request Response DMA registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x40); - for (i = 0; i < 32; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * DMA registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x50); - for (i = 0; i < 48; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * RISC hardware registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0); - for (i = 0; i < 16; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0xA0 + (i << 1)); - } - - /* - * RISC GP? registers - */ - for (j = 0; j < 8; j++) { - ISP_WRITE(isp, BIU_BLOCK + 0xA4, 0x2000 + (j << 9)); - for (i = 0; i < 16; i++) { - *ptr++ = - ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - } - - /* - * frame buffer hardware registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x10); - for (i = 0; i < 64; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * FPM B0 hardware registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x20); - for (i = 0; i < 64; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - - /* - * FPM B1 hardware registers - */ - ISP_WRITE(isp, BIU2100_CSR, 0x30); - for (i = 0; i < 64; i++) { - *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); - } - } else { - isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause"); - return; - } - isp_prt(isp, ISP_LOGALL, - "isp_fw_dump: RISC registers dumped successfully"); - ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); - for (i = 0; i < 100; i++) { - USEC_DELAY(100); - if (ISP_READ(isp, OUTMAILBOX0) == 0) { - break; - } - } - if (ISP_READ(isp, OUTMAILBOX0) != 0) { - isp_prt(isp, ISP_LOGERR, "Board Would Not Reset"); - return; - } - ISP_ENABLE_INTS(isp); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_READ_RAM_WORD; - mbs.param[1] = 0x800; - isp->isp_mbxworkp = (void *) ptr; - isp->isp_mbxwrk0 = 0xf7ff; /* continuation count */ - isp->isp_mbxwrk1 = 0x801; /* next SRAM address */ - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGWARN, - "RAM DUMP FAILED @ WORD %x", isp->isp_mbxwrk1); - return; - } - ptr = isp->isp_mbxworkp; /* finish fetch of final word */ - *ptr++ = isp->isp_mboxtmp[2]; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_READ_RAM_WORD_EXTENDED; - mbs.param[8] = 1; - isp->isp_mbxworkp = (void *) ptr; - isp->isp_mbxwrk0 = 0xffff; /* continuation count */ - isp->isp_mbxwrk1 = 0x1; /* next SRAM address */ - isp->isp_mbxwrk8 = 0x1; - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGWARN, - "RAM DUMP FAILED @ WORD %x", 0x10000 + isp->isp_mbxwrk1); - return; - } - ptr = isp->isp_mbxworkp; /* finish final word */ - *ptr++ = mbs.param[2]; - isp_prt(isp, ISP_LOGALL, "isp_fw_dump: SRAM dumped successfully"); - FCPARAM(isp)->isp_dump_data[0] = isp->isp_type; /* now used */ - (void) isp_async(isp, ISPASYNC_FW_DUMPED, 0); -} - -void -isp_fw_dump(ispsoftc_t *isp) -{ - if (IS_2200(isp)) - isp2200_fw_dump(isp); - else if (IS_23XX(isp)) - isp2300_fw_dump(isp); - else if (IS_24XX(isp)) - isp_prt(isp, ISP_LOGERR, "24XX dump method undefined"); - -} -#endif diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index beb8fa12d1e5..b6f172b664ee 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997-2006 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,39 +32,36 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include /* for use by isp_prt below */ #include #include #include #include -#if __FreeBSD_version >= 500000 -#include -#else #include -#endif #include #include -#if !defined(CAM_NEW_TRAN_CODE) && __FreeBSD_version >= 700025 -#define CAM_NEW_TRAN_CODE 1 +#if __FreeBSD_version < 800002 +#define THREAD_CREATE kthread_create +#else +#define THREAD_CREATE kproc_create #endif - MODULE_VERSION(isp, 1); MODULE_DEPEND(isp, cam, 1, 1, 1); int isp_announced = 0; -int isp_fabric_hysteresis = 5; -int isp_loop_down_limit = 300; /* default loop down limit */ +int isp_fabric_hysteresis = 3; +int isp_loop_down_limit = 60; /* default loop down limit */ int isp_change_is_bad = 0; /* "changed" devices are bad */ -int isp_quickboot_time = 15; /* don't wait more than N secs for loop up */ +int isp_quickboot_time = 7; /* don't wait more than N secs for loop up */ int isp_gone_device_time = 30; /* grace time before reporting device lost */ +int isp_autoconfig = 1; /* automatically attach/detach devices */ static const char *roles[4] = { "(none)", "Target", "Initiator", "Target/Initiator" }; -static const char prom3[] = - "PortID 0x%06x Departed from Target %u because of %s"; +static const char prom3[] = "Chan %d PortID 0x%06x Departed from Target %u because of %s"; +static const char rqo[] = "%s: Request Queue Overflow\n"; -static void isp_freeze_loopdown(ispsoftc_t *, char *); +static void isp_freeze_loopdown(ispsoftc_t *, int, char *); static d_ioctl_t ispioctl; static void isp_intr_enable(void *); static void isp_cam_async(void *, uint32_t, struct cam_path *, void *); @@ -73,100 +70,48 @@ static timeout_t isp_watchdog; static timeout_t isp_ldt; static void isp_kthread(void *); static void isp_action(struct cam_sim *, union ccb *); - -#if __FreeBSD_version < 700000 -ispfwfunc *isp_get_firmware_p = NULL; +#ifdef ISP_INTERNAL_TARGET +static void isp_target_thread_pi(void *); +static void isp_target_thread_fc(void *); #endif +static void isp_timer(void *); -#if __FreeBSD_version < 500000 -#define ISP_CDEV_MAJOR 248 -static struct cdevsw isp_cdevsw = { - /* open */ nullopen, - /* close */ nullclose, - /* read */ noread, - /* write */ nowrite, - /* ioctl */ ispioctl, - /* poll */ nopoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "isp", - /* maj */ ISP_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ D_TAPE, -}; -#define isp_sysctl_update(x) do { ; } while (0) -#else static struct cdevsw isp_cdevsw = { .d_version = D_VERSION, -#if __FreeBSD_version < 700037 - .d_flags = D_NEEDGIANT, -#endif .d_ioctl = ispioctl, .d_name = "isp", }; -static void isp_sysctl_update(ispsoftc_t *); -#endif -static ispsoftc_t *isplist = NULL; - -void -isp_attach(ispsoftc_t *isp) +static int +isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan) { - int primary, secondary; struct ccb_setasync csa; - struct cam_devq *devq; struct cam_sim *sim; struct cam_path *path; - /* - * Establish (in case of 12X0) which bus is the primary. - */ - - primary = 0; - secondary = 1; - - /* - * Create the device queue for our SIM(s). - */ - devq = cam_simq_alloc(isp->isp_maxcmds); - if (devq == NULL) { - return; - } - /* * Construct our SIM entry. */ - sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp, - device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); + sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, device_get_unit(isp->isp_dev), &isp->isp_osinfo.lock, isp->isp_maxcmds, isp->isp_maxcmds, devq); + if (sim == NULL) { - cam_simq_free(devq); - return; + return (ENOMEM); } - isp->isp_osinfo.ehook.ich_func = isp_intr_enable; - isp->isp_osinfo.ehook.ich_arg = isp; - ISP_UNLOCK(isp); - if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { - ISP_LOCK(isp); - cam_sim_free(sim, TRUE); - isp_prt(isp, ISP_LOGERR, - "could not establish interrupt enable hook"); - return; - } ISP_LOCK(isp); - - if (xpt_bus_register(sim, isp->isp_dev, primary) != CAM_SUCCESS) { - cam_sim_free(sim, TRUE); - return; + if (xpt_bus_register(sim, isp->isp_dev, chan) != CAM_SUCCESS) { + ISP_UNLOCK(isp); + cam_sim_free(sim, FALSE); + return (EIO); } + ISP_UNLOCK(isp); - if (xpt_create_path(&path, NULL, cam_sim_path(sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + if (xpt_create_path(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + ISP_LOCK(isp); xpt_bus_deregister(cam_sim_path(sim)); - cam_sim_free(sim, TRUE); - config_intrhook_disestablish(&isp->isp_osinfo.ehook); - return; + ISP_UNLOCK(isp); + cam_sim_free(sim, FALSE); + return (ENXIO); } xpt_setup_ccb(&csa.ccb_h, path, 5); @@ -175,188 +120,195 @@ isp_attach(ispsoftc_t *isp) csa.callback = isp_cam_async; csa.callback_arg = sim; xpt_action((union ccb *)&csa); - isp->isp_sim = sim; - isp->isp_path = path; - /* - * If we have a second channel, construct SIM entry for that. - */ - if (IS_DUALBUS(isp)) { - sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp, - device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); - if (sim == NULL) { - xpt_bus_deregister(cam_sim_path(isp->isp_sim)); - xpt_free_path(isp->isp_path); - cam_simq_free(devq); - config_intrhook_disestablish(&isp->isp_osinfo.ehook); - return; + if (IS_SCSI(isp)) { + struct isp_spi *spi = ISP_SPI_PC(isp, chan); + spi->sim = sim; + spi->path = path; +#ifdef ISP_INTERNAL_TARGET + ISP_SET_PC(isp, chan, proc_active, 1); + if (THREAD_CREATE(isp_target_thread_pi, spi, &spi->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { + ISP_SET_PC(isp, chan, proc_active, 0); + isp_prt(isp, ISP_LOGERR, "cannot create test target thread"); } - if (xpt_bus_register(sim, isp->isp_dev, secondary) != - CAM_SUCCESS) { - xpt_bus_deregister(cam_sim_path(isp->isp_sim)); - xpt_free_path(isp->isp_path); - cam_sim_free(sim, TRUE); - config_intrhook_disestablish(&isp->isp_osinfo.ehook); - return; - } - - if (xpt_create_path(&path, NULL, cam_sim_path(sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { - xpt_bus_deregister(cam_sim_path(isp->isp_sim)); - xpt_free_path(isp->isp_path); - xpt_bus_deregister(cam_sim_path(sim)); - cam_sim_free(sim, TRUE); - config_intrhook_disestablish(&isp->isp_osinfo.ehook); - return; - } - - xpt_setup_ccb(&csa.ccb_h, path, 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = isp_cam_async; - csa.callback_arg = sim; - xpt_action((union ccb *)&csa); - isp->isp_sim2 = sim; - isp->isp_path2 = path; - } - - /* - * Create device nodes - */ - ISP_UNLOCK(isp); - (void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT, - GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev)); - isp_sysctl_update(isp); - ISP_LOCK(isp); - - if (isp->isp_role != ISP_ROLE_NONE) { - isp->isp_state = ISP_RUNSTATE; - ISP_ENABLE_INTS(isp); - } - if (isplist == NULL) { - isplist = isp; - } else { - ispsoftc_t *tmp = isplist; - while (tmp->isp_osinfo.next) { - tmp = tmp->isp_osinfo.next; - } - tmp->isp_osinfo.next = isp; - } - - /* - * Create a kernel thread for fibre channel instances. - */ - if (IS_FC(isp)) { - isp_callout_init(&isp->isp_osinfo.ldt); - isp_callout_init(&isp->isp_osinfo.gdt); - ISP_UNLOCK(isp); -#if __FreeBSD_version >= 500000 - if (kproc_create(isp_kthread, isp, &isp->isp_osinfo.kproc, - RFHIGHPID, 0, "%s: fc_thrd", - device_get_nameunit(isp->isp_dev))) -#else - if (kproc_create(isp_kthread, isp, &isp->isp_osinfo.kproc, - "%s: fc_thrd", device_get_nameunit(isp->isp_dev))) #endif - { + } else { + struct isp_fc *fc = ISP_FC_PC(isp, chan); + + fc->sim = sim; + fc->path = path; + fc->isp = isp; + + callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0); + callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0); + + if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { + xpt_free_path(fc->path); ISP_LOCK(isp); - xpt_bus_deregister(cam_sim_path(sim)); - cam_sim_free(sim, TRUE); - config_intrhook_disestablish(&isp->isp_osinfo.ehook); - isp_prt(isp, ISP_LOGERR, "could not create kthread"); - return; + xpt_bus_deregister(cam_sim_path(fc->sim)); + ISP_UNLOCK(isp); + cam_sim_free(fc->sim, FALSE); } - ISP_LOCK(isp); /* * We start by being "loop down" if we have an initiator role */ - if (isp->isp_role & ISP_ROLE_INITIATOR) { - isp_freeze_loopdown(isp, "isp_attach"); - isp->isp_osinfo.ldt_running = 1; - callout_reset(&isp->isp_osinfo.ldt, - isp_quickboot_time * hz, isp_ldt, isp); - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Starting Initial Loop Down Timer"); + ISP_LOCK(isp); + if ((FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) && fc->ldt_running == 0) { + isp_freeze_loopdown(isp, chan, "isp_attach"); + fc->ldt_running = 1; + callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime); } + ISP_UNLOCK(isp); +#ifdef ISP_INTERNAL_TARGET + ISP_SET_PC(isp, chan, proc_active, 1); + if (THREAD_CREATE(isp_target_thread_fc, fc, &fc->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) { + ISP_SET_PC(isp, chan, proc_active, 0); + isp_prt(isp, ISP_LOGERR, "cannot create test target thread"); + } +#endif + } + return (0); +} + +int +isp_attach(ispsoftc_t *isp) +{ + const char *nu = device_get_nameunit(isp->isp_osinfo.dev); + int du = device_get_unit(isp->isp_dev); + int chan; + + isp->isp_osinfo.ehook.ich_func = isp_intr_enable; + isp->isp_osinfo.ehook.ich_arg = isp; + if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { + isp_prt(isp, ISP_LOGERR, "could not establish interrupt enable hook"); + return (-EIO); + } + isp->isp_osinfo.ehook_active = 1; + + + /* + * Create the device queue for our SIM(s). + */ + isp->isp_osinfo.devq = cam_simq_alloc(isp->isp_maxcmds); + if (isp->isp_osinfo.devq == NULL) { + config_intrhook_disestablish(&isp->isp_osinfo.ehook); + return (EIO); + } + + for (chan = 0; chan < isp->isp_nchan; chan++) { + if (isp_attach_chan(isp, isp->isp_osinfo.devq, chan)) { + goto unwind; + } + } + + callout_init_mtx(&isp->isp_osinfo.tmo, &isp->isp_osinfo.lock, 0); + callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp); + isp->isp_osinfo.timer_active = 1; + + isp->isp_osinfo.cdev = make_dev(&isp_cdevsw, du, UID_ROOT, GID_OPERATOR, 0600, "%s", nu); + if (isp->isp_osinfo.cdev) { + isp->isp_osinfo.cdev->si_drv1 = isp; + } + return (0); + +unwind: + while (--chan >= 0) { + struct cam_sim *sim; + struct cam_path *path; + if (IS_FC(isp)) { + sim = ISP_FC_PC(isp, chan)->sim; + path = ISP_FC_PC(isp, chan)->path; + } else { + sim = ISP_SPI_PC(isp, chan)->sim; + path = ISP_SPI_PC(isp, chan)->path; + } + xpt_free_path(path); + ISP_LOCK(isp); + xpt_bus_deregister(cam_sim_path(sim)); + ISP_UNLOCK(isp); + cam_sim_free(sim, FALSE); + } + if (isp->isp_osinfo.ehook_active) { + config_intrhook_disestablish(&isp->isp_osinfo.ehook); + isp->isp_osinfo.ehook_active = 0; + } + if (isp->isp_osinfo.cdev) { + destroy_dev(isp->isp_osinfo.cdev); + isp->isp_osinfo.cdev = NULL; + } + cam_simq_free(isp->isp_osinfo.devq); + isp->isp_osinfo.devq = NULL; + return (-1); +} + +void +isp_detach(ispsoftc_t *isp) +{ + int chan; + + ISP_LOCK(isp); + if (isp->isp_osinfo.timer_active) { + callout_stop(&isp->isp_osinfo.tmo); + isp->isp_osinfo.timer_active = 0; + } + ISP_UNLOCK(isp); + for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) { + struct cam_sim *sim; + struct cam_path *path; + if (IS_FC(isp)) { + sim = ISP_FC_PC(isp, chan)->sim; + path = ISP_FC_PC(isp, chan)->path; + } else { + sim = ISP_SPI_PC(isp, chan)->sim; + path = ISP_SPI_PC(isp, chan)->path; + } + xpt_free_path(path); + ISP_LOCK(isp); + xpt_bus_deregister(cam_sim_path(sim)); + ISP_UNLOCK(isp); + cam_sim_free(sim, FALSE); + } + if (isp->isp_osinfo.cdev) { + destroy_dev(isp->isp_osinfo.cdev); + isp->isp_osinfo.cdev = NULL; + } + if (isp->isp_osinfo.ehook_active) { + config_intrhook_disestablish(&isp->isp_osinfo.ehook); + isp->isp_osinfo.ehook_active = 0; + } + if (isp->isp_osinfo.devq == NULL) { + cam_simq_free(isp->isp_osinfo.devq); + isp->isp_osinfo.devq = NULL; } } static void -isp_freeze_loopdown(ispsoftc_t *isp, char *msg) +isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg) { - if (isp->isp_osinfo.simqfrozen == 0) { - isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg); - isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; - xpt_freeze_simq(isp->isp_sim, 1); - } else { - isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg); - isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; + if (IS_FC(isp)) { + struct isp_fc *fc = ISP_FC_PC(isp, chan); + if (fc->simqfrozen == 0) { + isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown) chan %d", msg, chan); + fc->simqfrozen = SIMQFRZ_LOOPDOWN; + xpt_freeze_simq(fc->sim, 1); + } else { + isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown) chan %d", msg, chan); + fc->simqfrozen |= SIMQFRZ_LOOPDOWN; + } } } -#if __FreeBSD_version < 500000 -#define _DEV dev_t -#define _IOP struct proc -#else -#define _IOP struct thread -#define _DEV struct cdev * -#endif - static int -ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) +ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) { ispsoftc_t *isp; - int nr, retval = ENOTTY; + int nr, chan, retval = ENOTTY; - isp = isplist; - while (isp) { - if (dev2unit(dev) == device_get_unit(isp->isp_dev)) { - break; - } - isp = isp->isp_osinfo.next; - } - if (isp == NULL) { - return (ENXIO); - } + isp = dev->si_drv1; switch (c) { -#ifdef ISP_FW_CRASH_DUMP - case ISP_GET_FW_CRASH_DUMP: - if (IS_FC(isp)) { - uint16_t *ptr = FCPARAM(isp)->isp_dump_data; - size_t sz; - - retval = 0; - if (IS_2200(isp)) { - sz = QLA2200_RISC_IMAGE_DUMP_SIZE; - } else { - sz = QLA2300_RISC_IMAGE_DUMP_SIZE; - } - if (ptr && *ptr) { - void *uaddr = *((void **) addr); - if (copyout(ptr, uaddr, sz)) { - retval = EFAULT; - } else { - *ptr = 0; - } - } else { - retval = ENXIO; - } - } - break; - case ISP_FORCE_CRASH_DUMP: - if (IS_FC(isp)) { - ISP_LOCK(isp); - isp_freeze_loopdown(isp, - "ispioctl(ISP_FORCE_CRASH_DUMP)"); - isp_fw_dump(isp); - isp_reinit(isp); - ISP_UNLOCK(isp); - retval = 0; - } - break; -#endif case ISP_SDBLEV: { int olddblev = isp->isp_dblev; @@ -366,28 +318,65 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) break; } case ISP_GETROLE: - *(int *)addr = isp->isp_role; + chan = *(int *)addr; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = -ENXIO; + break; + } + if (IS_FC(isp)) { + *(int *)addr = FCPARAM(isp, chan)->role; + } else { + *(int *)addr = SDPARAM(isp, chan)->role; + } retval = 0; break; case ISP_SETROLE: nr = *(int *)addr; + chan = nr >> 8; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = -ENXIO; + break; + } + nr &= 0xff; if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) { retval = EINVAL; break; } - *(int *)addr = isp->isp_role; - isp->isp_role = nr; - /* FALLTHROUGH */ + if (IS_FC(isp)) { + *(int *)addr = FCPARAM(isp, chan)->role; +#ifdef ISP_INTERNAL_TARGET + ISP_LOCK(isp); + retval = isp_fc_change_role(isp, chan, nr); + ISP_UNLOCK(isp); +#else + FCPARAM(isp, chan)->role = nr; +#endif + } else { + *(int *)addr = SDPARAM(isp, chan)->role; + SDPARAM(isp, chan)->role = nr; + } + retval = 0; + break; + case ISP_RESETHBA: ISP_LOCK(isp); - isp_reinit(isp); +#ifdef ISP_TARGET_MODE + isp_del_all_wwn_entries(isp, ISP_NOCHAN); +#endif + isp_reinit(isp, 0); ISP_UNLOCK(isp); retval = 0; break; + case ISP_RESCAN: if (IS_FC(isp)) { + chan = *(int *)addr; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = -ENXIO; + break; + } ISP_LOCK(isp); - if (isp_fc_runstate(isp, 5 * 1000000)) { + if (isp_fc_runstate(isp, chan, 5 * 1000000)) { retval = EIO; } else { retval = 0; @@ -395,10 +384,16 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) ISP_UNLOCK(isp); } break; + case ISP_FC_LIP: if (IS_FC(isp)) { + chan = *(int *)addr; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = -ENXIO; + break; + } ISP_LOCK(isp); - if (isp_control(isp, ISPCTL_SEND_LIP, 0)) { + if (isp_control(isp, ISPCTL_SEND_LIP, chan)) { retval = EIO; } else { retval = 0; @@ -418,8 +413,8 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) retval = EINVAL; break; } - lp = &FCPARAM(isp)->portdb[ifc->loopid]; - if (lp->state == FC_PORTDB_STATE_VALID) { + lp = &FCPARAM(isp, ifc->chan)->portdb[ifc->loopid]; + if (lp->state == FC_PORTDB_STATE_VALID || lp->target_mode) { ifc->role = lp->roles; ifc->loopid = lp->handle; ifc->portid = lp->portid; @@ -435,7 +430,7 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) { isp_stats_t *sp = (isp_stats_t *) addr; - MEMZERO(sp, sizeof (*sp)); + ISP_MEMZERO(sp, sizeof (*sp)); sp->isp_stat_version = ISP_STATS_VERSION; sp->isp_type = isp->isp_type; sp->isp_revision = isp->isp_revision; @@ -468,20 +463,33 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) case ISP_FC_GETHINFO: { struct isp_hba_device *hba = (struct isp_hba_device *) addr; - MEMZERO(hba, sizeof (*hba)); + int chan = hba->fc_channel; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = ENXIO; + break; + } hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev); hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev); hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev); + hba->fc_nchannels = isp->isp_nchan; if (IS_FC(isp)) { - hba->fc_speed = FCPARAM(isp)->isp_gbspeed; - hba->fc_scsi_supported = 1; - hba->fc_topology = FCPARAM(isp)->isp_topo + 1; - hba->fc_loopid = FCPARAM(isp)->isp_loopid; - hba->nvram_node_wwn = FCPARAM(isp)->isp_wwnn_nvram; - hba->nvram_port_wwn = FCPARAM(isp)->isp_wwpn_nvram; - hba->active_node_wwn = ISP_NODEWWN(isp); - hba->active_port_wwn = ISP_PORTWWN(isp); + hba->fc_nports = MAX_FC_TARG; + hba->fc_speed = FCPARAM(isp, hba->fc_channel)->isp_gbspeed; + hba->fc_topology = FCPARAM(isp, chan)->isp_topo + 1; + hba->fc_loopid = FCPARAM(isp, chan)->isp_loopid; + hba->nvram_node_wwn = FCPARAM(isp, chan)->isp_wwnn_nvram; + hba->nvram_port_wwn = FCPARAM(isp, chan)->isp_wwpn_nvram; + hba->active_node_wwn = FCPARAM(isp, chan)->isp_wwnn; + hba->active_port_wwn = FCPARAM(isp, chan)->isp_wwpn; + } else { + hba->fc_nports = MAX_TARGETS; + hba->fc_speed = 0; + hba->fc_topology = 0; + hba->nvram_node_wwn = 0ull; + hba->nvram_port_wwn = 0ull; + hba->active_node_wwn = 0ull; + hba->active_port_wwn = 0ull; } retval = 0; break; @@ -497,55 +505,155 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) break; } - memset(&mbs, 0, sizeof (mbs)); + chan = fct->chan; + if (chan < 0 || chan >= isp->isp_nchan) { + retval = -ENXIO; + break; + } + needmarker = retval = 0; loopid = fct->loopid; - if (FCPARAM(isp)->isp_2klogin == 0) { - loopid <<= 8; - } - switch (fct->action) { - case IPT_CLEAR_ACA: - mbs.param[0] = MBOX_CLEAR_ACA; - mbs.param[1] = loopid; - mbs.param[2] = fct->lun; - break; - case IPT_TARGET_RESET: - mbs.param[0] = MBOX_TARGET_RESET; - mbs.param[1] = loopid; - needmarker = 1; - break; - case IPT_LUN_RESET: - mbs.param[0] = MBOX_LUN_RESET; - mbs.param[1] = loopid; - mbs.param[2] = fct->lun; - needmarker = 1; - break; - case IPT_CLEAR_TASK_SET: - mbs.param[0] = MBOX_CLEAR_TASK_SET; - mbs.param[1] = loopid; - mbs.param[2] = fct->lun; - needmarker = 1; - break; - case IPT_ABORT_TASK_SET: - mbs.param[0] = MBOX_ABORT_TASK_SET; - mbs.param[1] = loopid; - mbs.param[2] = fct->lun; - needmarker = 1; - break; - default: - retval = EINVAL; - break; - } - if (retval == 0) { - if (needmarker) { - isp->isp_sendmarker |= 1; + ISP_LOCK(isp); + if (IS_24XX(isp)) { + uint8_t local[QENTRY_LEN]; + isp24xx_tmf_t *tmf; + isp24xx_statusreq_t *sp; + fcparam *fcp = FCPARAM(isp, chan); + fcportdb_t *lp; + int i; + + for (i = 0; i < MAX_FC_TARG; i++) { + lp = &fcp->portdb[i]; + if (lp->handle == loopid) { + break; + } } - ISP_LOCK(isp); + if (i == MAX_FC_TARG) { + retval = ENXIO; + ISP_UNLOCK(isp); + break; + } + /* XXX VALIDATE LP XXX */ + tmf = (isp24xx_tmf_t *) local; + ISP_MEMZERO(tmf, QENTRY_LEN); + tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT; + tmf->tmf_header.rqs_entry_count = 1; + tmf->tmf_nphdl = lp->handle; + tmf->tmf_delay = 2; + tmf->tmf_timeout = 2; + tmf->tmf_tidlo = lp->portid; + tmf->tmf_tidhi = lp->portid >> 16; + tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); + tmf->tmf_lun[1] = fct->lun & 0xff; + if (fct->lun >= 256) { + tmf->tmf_lun[0] = 0x40 | (fct->lun >> 8); + } + switch (fct->action) { + case IPT_CLEAR_ACA: + tmf->tmf_flags = ISP24XX_TMF_CLEAR_ACA; + break; + case IPT_TARGET_RESET: + tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET; + needmarker = 1; + break; + case IPT_LUN_RESET: + tmf->tmf_flags = ISP24XX_TMF_LUN_RESET; + needmarker = 1; + break; + case IPT_CLEAR_TASK_SET: + tmf->tmf_flags = ISP24XX_TMF_CLEAR_TASK_SET; + needmarker = 1; + break; + case IPT_ABORT_TASK_SET: + tmf->tmf_flags = ISP24XX_TMF_ABORT_TASK_SET; + needmarker = 1; + break; + default: + retval = EINVAL; + break; + } + if (retval) { + ISP_UNLOCK(isp); + break; + } + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + ISP_UNLOCK(isp); + retval = ENOMEM; + break; + } + isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN); + sp = (isp24xx_statusreq_t *) local; + sp->req_completion_status = 1; retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - ISP_UNLOCK(isp); - if (retval) + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN); + isp_get_24xx_response(isp, &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp); + FC_SCRATCH_RELEASE(isp, chan); + if (retval || sp->req_completion_status != 0) { + FC_SCRATCH_RELEASE(isp, chan); retval = EIO; + } + if (retval == 0) { + if (needmarker) { + fcp->sendmarker = 1; + } + } + } else { + MBSINIT(&mbs, 0, MBLOGALL, 0); + if (ISP_CAP_2KLOGIN(isp) == 0) { + loopid <<= 8; + } + switch (fct->action) { + case IPT_CLEAR_ACA: + mbs.param[0] = MBOX_CLEAR_ACA; + mbs.param[1] = loopid; + mbs.param[2] = fct->lun; + break; + case IPT_TARGET_RESET: + mbs.param[0] = MBOX_TARGET_RESET; + mbs.param[1] = loopid; + needmarker = 1; + break; + case IPT_LUN_RESET: + mbs.param[0] = MBOX_LUN_RESET; + mbs.param[1] = loopid; + mbs.param[2] = fct->lun; + needmarker = 1; + break; + case IPT_CLEAR_TASK_SET: + mbs.param[0] = MBOX_CLEAR_TASK_SET; + mbs.param[1] = loopid; + mbs.param[2] = fct->lun; + needmarker = 1; + break; + case IPT_ABORT_TASK_SET: + mbs.param[0] = MBOX_ABORT_TASK_SET; + mbs.param[1] = loopid; + mbs.param[2] = fct->lun; + needmarker = 1; + break; + default: + retval = EINVAL; + break; + } + if (retval == 0) { + if (needmarker) { + FCPARAM(isp, chan)->sendmarker = 1; + } + retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (retval) { + retval = EIO; + } + } } + ISP_UNLOCK(isp); break; } default: @@ -554,663 +662,795 @@ ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td) return (retval); } -#if __FreeBSD_version >= 500000 -static void -isp_sysctl_update(ispsoftc_t *isp) -{ - struct sysctl_ctx_list *ctx = - device_get_sysctl_ctx(isp->isp_osinfo.dev); - struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev); - - if (IS_SCSI(isp)) { - return; - } - - snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn, - sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x", - (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp)); - - snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn, - sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x", - (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp)); - - SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0, - "World Wide Node Name"); - - SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0, - "World Wide Port Name"); - - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "loop_down_limit", - CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0, - "How long to wait for loop to come back up"); - - SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "gone_device_time", - CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0, - "How long to wait for a device to reappear"); -} -#endif - static void isp_intr_enable(void *arg) { + int chan; ispsoftc_t *isp = arg; ISP_LOCK(isp); - if (isp->isp_role != ISP_ROLE_NONE) { - ISP_ENABLE_INTS(isp); + for (chan = 0; chan < isp->isp_nchan; chan++) { + if (IS_FC(isp)) { + if (FCPARAM(isp, chan)->role != ISP_ROLE_NONE) { + ISP_ENABLE_INTS(isp); + break; + } + } else { + if (SDPARAM(isp, chan)->role != ISP_ROLE_NONE) { + ISP_ENABLE_INTS(isp); + break; + } + } } ISP_UNLOCK(isp); /* Release our hook so that the boot can continue. */ config_intrhook_disestablish(&isp->isp_osinfo.ehook); } +/* + * Local Inlines + */ + +static ISP_INLINE int isp_get_pcmd(ispsoftc_t *, union ccb *); +static ISP_INLINE void isp_free_pcmd(ispsoftc_t *, union ccb *); + +static ISP_INLINE int +isp_get_pcmd(ispsoftc_t *isp, union ccb *ccb) +{ + ISP_PCMD(ccb) = isp->isp_osinfo.pcmd_free; + if (ISP_PCMD(ccb) == NULL) { + return (-1); + } + isp->isp_osinfo.pcmd_free = ((struct isp_pcmd *)ISP_PCMD(ccb))->next; + return (0); +} + +static ISP_INLINE void +isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb) +{ + ((struct isp_pcmd *)ISP_PCMD(ccb))->next = isp->isp_osinfo.pcmd_free; + isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb); + ISP_PCMD(ccb) = NULL; +} /* * Put the target mode functions here, because some are inlines */ #ifdef ISP_TARGET_MODE - -static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t); -static __inline int are_any_luns_enabled(ispsoftc_t *, int); -static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); -static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *); -static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int); -static cam_status -create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); +static ISP_INLINE int is_lun_enabled(ispsoftc_t *, int, lun_id_t); +static ISP_INLINE tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t); +static ISP_INLINE tstate_t *get_lun_statep_from_tag(ispsoftc_t *, int, uint32_t); +static ISP_INLINE void rls_lun_statep(ispsoftc_t *, tstate_t *); +static ISP_INLINE inot_private_data_t *get_ntp_from_tagdata(ispsoftc_t *, uint32_t, uint32_t, tstate_t **); +static ISP_INLINE atio_private_data_t *isp_get_atpd(ispsoftc_t *, tstate_t *, uint32_t); +static ISP_INLINE void isp_put_atpd(ispsoftc_t *, tstate_t *, atio_private_data_t *); +static ISP_INLINE inot_private_data_t *isp_get_ntpd(ispsoftc_t *, tstate_t *); +static ISP_INLINE inot_private_data_t *isp_find_ntpd(ispsoftc_t *, tstate_t *, uint32_t, uint32_t); +static ISP_INLINE void isp_put_ntpd(ispsoftc_t *, tstate_t *, inot_private_data_t *); +static cam_status create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **); static void destroy_lun_state(ispsoftc_t *, tstate_t *); -static int isp_en_lun(ispsoftc_t *, union ccb *); +static void isp_enable_lun(ispsoftc_t *, union ccb *); +static void isp_enable_deferred_luns(ispsoftc_t *, int); +static cam_status isp_enable_deferred(ispsoftc_t *, int, lun_id_t); +static void isp_disable_lun(ispsoftc_t *, union ccb *); +static int isp_enable_target_mode(ispsoftc_t *, int); static void isp_ledone(ispsoftc_t *, lun_entry_t *); -static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *); static timeout_t isp_refire_putback_atio; static void isp_complete_ctio(union ccb *); static void isp_target_putback_atio(union ccb *); static void isp_target_start_ctio(ispsoftc_t *, union ccb *); -static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); -static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); -static int isp_handle_platform_ctio(ispsoftc_t *, void *); -static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); -static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); +static void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); +static void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); +static void isp_handle_platform_atio7(ispsoftc_t *, at7_entry_t *); +static void isp_handle_platform_ctio(ispsoftc_t *, void *); +static void isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *); +static void isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *); +static void isp_handle_platform_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *); +static int isp_handle_platform_target_notify_ack(ispsoftc_t *, isp_notify_t *); +static void isp_handle_platform_target_tmf(ispsoftc_t *, isp_notify_t *); +static void isp_target_mark_aborted(ispsoftc_t *, union ccb *); +static void isp_target_mark_aborted_early(ispsoftc_t *, tstate_t *, uint32_t); -static __inline int +static ISP_INLINE int is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun) { tstate_t *tptr; - tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; - if (tptr == NULL) { - return (0); - } - do { - if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) { + struct tslist *lhp; + + ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(lun)], lhp); + SLIST_FOREACH(tptr, lhp, next) { + if (xpt_path_lun_id(tptr->owner) == lun) { return (1); } - } while ((tptr = tptr->next) != NULL); + } return (0); } -static __inline int -are_any_luns_enabled(ispsoftc_t *isp, int port) +static void +dump_tstates(ispsoftc_t *isp, int bus) { - int lo, hi; - if (IS_DUALBUS(isp)) { - lo = (port * (LUN_HASH_SIZE >> 1)); - hi = lo + (LUN_HASH_SIZE >> 1); - } else { - lo = 0; - hi = LUN_HASH_SIZE; + int i, j; + struct tslist *lhp; + tstate_t *tptr = NULL; + + if (bus >= isp->isp_nchan) { + return; } - for (lo = 0; lo < hi; lo++) { - if (isp->isp_osinfo.lun_hash[lo]) { - return (1); + for (i = 0; i < LUN_HASH_SIZE; i++) { + ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); + j = 0; + SLIST_FOREACH(tptr, lhp, next) { + xpt_print(tptr->owner, "[%d, %d] atio_cnt=%d inot_cnt=%d\n", i, j, tptr->atio_count, tptr->inot_count); + j++; } } - return (0); } -static __inline tstate_t * +static ISP_INLINE tstate_t * get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun) { tstate_t *tptr = NULL; + struct tslist *lhp; + int i; - if (lun == CAM_LUN_WILDCARD) { - if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) { - tptr = &isp->isp_osinfo.tsdflt[bus]; - tptr->hold++; - return (tptr); + if (bus < isp->isp_nchan) { + for (i = 0; i < LUN_HASH_SIZE; i++) { + ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); + SLIST_FOREACH(tptr, lhp, next) { + if (xpt_path_lun_id(tptr->owner) == lun) { + tptr->hold++; + return (tptr); + } + } } - return (NULL); - } else { - tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)]; - if (tptr == NULL) { - return (NULL); - } - } - - do { - if (tptr->lun == lun && tptr->bus == bus) { - tptr->hold++; - return (tptr); - } - } while ((tptr = tptr->next) != NULL); - return (tptr); -} - -static __inline void -rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) -{ - if (tptr->hold) - tptr->hold--; -} - -static __inline atio_private_data_t * -isp_get_atpd(ispsoftc_t *isp, int tag) -{ - atio_private_data_t *atp; - for (atp = isp->isp_osinfo.atpdp; - atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) { - if (atp->tag == tag) - return (atp); } return (NULL); } +static ISP_INLINE tstate_t * +get_lun_statep_from_tag(ispsoftc_t *isp, int bus, uint32_t tagval) +{ + tstate_t *tptr = NULL; + atio_private_data_t *atp; + struct tslist *lhp; + int i; + + if (bus < isp->isp_nchan && tagval != 0) { + for (i = 0; i < LUN_HASH_SIZE; i++) { + ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); + SLIST_FOREACH(tptr, lhp, next) { + atp = isp_get_atpd(isp, tptr, tagval); + if (atp && atp->tag == tagval) { + tptr->hold++; + return (tptr); + } + } + } + } + return (NULL); +} + +static ISP_INLINE inot_private_data_t * +get_ntp_from_tagdata(ispsoftc_t *isp, uint32_t tag_id, uint32_t seq_id, tstate_t **rslt) +{ + inot_private_data_t *ntp; + tstate_t *tptr; + struct tslist *lhp; + int bus, i; + + for (bus = 0; bus < isp->isp_nchan; bus++) { + for (i = 0; i < LUN_HASH_SIZE; i++) { + ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); + SLIST_FOREACH(tptr, lhp, next) { + ntp = isp_find_ntpd(isp, tptr, tag_id, seq_id); + if (ntp) { + *rslt = tptr; + tptr->hold++; + return (ntp); + } + } + } + } + return (NULL); +} +static ISP_INLINE void +rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr) +{ + KASSERT((tptr->hold), ("tptr not held")); + tptr->hold--; +} + +static void +isp_tmcmd_restart(ispsoftc_t *isp) +{ + inot_private_data_t *ntp; + tstate_t *tptr; + struct tslist *lhp; + int bus, i; + + for (bus = 0; bus < isp->isp_nchan; bus++) { + for (i = 0; i < LUN_HASH_SIZE; i++) { + ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp); + SLIST_FOREACH(tptr, lhp, next) { + inot_private_data_t *restart_queue = tptr->restart_queue; + tptr->restart_queue = NULL; + while (restart_queue) { + ntp = restart_queue; + restart_queue = ntp->rd.nt.nt_hba; + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid); + isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data); + } else { + isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid); + isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data); + } + isp_put_ntpd(isp, tptr, ntp); + if (tptr->restart_queue && restart_queue != NULL) { + ntp = tptr->restart_queue; + tptr->restart_queue = restart_queue; + while (restart_queue->rd.nt.nt_hba) { + restart_queue = restart_queue->rd.nt.nt_hba; + } + restart_queue->rd.nt.nt_hba = ntp; + break; + } + } + } + } + } +} + +static ISP_INLINE atio_private_data_t * +isp_get_atpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag) +{ + atio_private_data_t *atp; + + if (tag == 0) { + atp = tptr->atfree; + if (atp) { + tptr->atfree = atp->next; + } + return (atp); + } + for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { + if (atp->tag == tag) { + return (atp); + } + } + return (NULL); +} + +static ISP_INLINE void +isp_put_atpd(ispsoftc_t *isp, tstate_t *tptr, atio_private_data_t *atp) +{ + atp->tag = 0; + atp->dead = 0; + atp->next = tptr->atfree; + tptr->atfree = atp; +} + +static void +isp_dump_atpd(ispsoftc_t *isp, tstate_t *tptr) +{ + atio_private_data_t *atp; + const char *states[8] = { "Free", "ATIO", "CAM", "CTIO", "LAST_CTIO", "PDON", "?6", "7" }; + + for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { + if (atp->tag == 0) { + continue; + } + xpt_print(tptr->owner, "ATP: [0x%x] origdlen %u bytes_xfrd %u last_xfr %u lun %u nphdl 0x%04x s_id 0x%06x d_id 0x%06x oxid 0x%04x state %s\n", + atp->tag, atp->orig_datalen, atp->bytes_xfered, atp->last_xframt, atp->lun, atp->nphdl, atp->sid, atp->portid, atp->oxid, states[atp->state & 0x7]); + } +} + + +static ISP_INLINE inot_private_data_t * +isp_get_ntpd(ispsoftc_t *isp, tstate_t *tptr) +{ + inot_private_data_t *ntp; + ntp = tptr->ntfree; + if (ntp) { + tptr->ntfree = ntp->next; + } + return (ntp); +} + +static ISP_INLINE inot_private_data_t * +isp_find_ntpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id, uint32_t seq_id) +{ + inot_private_data_t *ntp; + for (ntp = tptr->ntpool; ntp < &tptr->ntpool[ATPDPSIZE]; ntp++) { + if (ntp->rd.tag_id == tag_id && ntp->rd.seq_id == seq_id) { + return (ntp); + } + } + return (NULL); +} + +static ISP_INLINE void +isp_put_ntpd(ispsoftc_t *isp, tstate_t *tptr, inot_private_data_t *ntp) +{ + ntp->rd.tag_id = ntp->rd.seq_id = 0; + ntp->next = tptr->ntfree; + tptr->ntfree = ntp; +} + static cam_status -create_lun_state(ispsoftc_t *isp, int bus, - struct cam_path *path, tstate_t **rslt) +create_lun_state(ispsoftc_t *isp, int bus, struct cam_path *path, tstate_t **rslt) { cam_status status; lun_id_t lun; - int hfx; - tstate_t *tptr, *new; + struct tslist *lhp; + tstate_t *tptr; + int i; lun = xpt_path_lun_id(path); - if (lun >= ISP_MAX_LUNS(isp)) { - return (CAM_LUN_INVALID); + if (lun != CAM_LUN_WILDCARD) { + if (lun >= ISP_MAX_LUNS(isp)) { + return (CAM_LUN_INVALID); + } } if (is_lun_enabled(isp, bus, lun)) { return (CAM_LUN_ALRDY_ENA); } - new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); - if (new == NULL) { + tptr = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); + if (tptr == NULL) { return (CAM_RESRC_UNAVAIL); } - - status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path), - xpt_path_target_id(path), xpt_path_lun_id(path)); + status = xpt_create_path(&tptr->owner, NULL, xpt_path_path_id(path), xpt_path_target_id(path), lun); if (status != CAM_REQ_CMP) { - free(new, M_DEVBUF); + free(tptr, M_DEVBUF); return (status); } - new->bus = bus; - new->lun = lun; - SLIST_INIT(&new->atios); - SLIST_INIT(&new->inots); - new->hold = 1; - - hfx = LUN_HASH_FUNC(isp, new->bus, new->lun); - tptr = isp->isp_osinfo.lun_hash[hfx]; - if (tptr == NULL) { - isp->isp_osinfo.lun_hash[hfx] = new; - } else { - while (tptr->next) - tptr = tptr->next; - tptr->next = new; + SLIST_INIT(&tptr->atios); + SLIST_INIT(&tptr->inots); + for (i = 0; i < ATPDPSIZE-1; i++) { + tptr->atpool[i].next = &tptr->atpool[i+1]; + tptr->ntpool[i].next = &tptr->ntpool[i+1]; } - *rslt = new; + tptr->atfree = tptr->atpool; + tptr->ntfree = tptr->ntpool; + tptr->hold = 1; + ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp); + SLIST_INSERT_HEAD(lhp, tptr, next); + *rslt = tptr; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, path, "created tstate\n"); return (CAM_REQ_CMP); } -static __inline void +static ISP_INLINE void destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr) { - int hfx; - tstate_t *lw, *pw; - - if (tptr->hold) { - return; - } - hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun); - pw = isp->isp_osinfo.lun_hash[hfx]; - if (pw == NULL) { - return; - } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) { - isp->isp_osinfo.lun_hash[hfx] = pw->next; - } else { - lw = pw; - pw = lw->next; - while (pw) { - if (pw->lun == tptr->lun && pw->bus == tptr->bus) { - lw->next = pw->next; - break; - } - lw = pw; - pw = pw->next; - } - if (pw == NULL) { - return; - } - } + struct tslist *lhp; + KASSERT((tptr->hold == 0), ("tptr still held")); + ISP_GET_PC_ADDR(isp, xpt_path_path_id(tptr->owner), lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp); + SLIST_REMOVE(lhp, tptr, tstate, next); + xpt_free_path(tptr->owner); free(tptr, M_DEVBUF); } /* - * Enable luns. + * Enable a lun. */ -static int -isp_en_lun(ispsoftc_t *isp, union ccb *ccb) +static void +isp_enable_lun(ispsoftc_t *isp, union ccb *ccb) { - struct ccb_en_lun *cel = &ccb->cel; tstate_t *tptr = NULL; - uint32_t seq; - int bus, cmd, av, wildcard, tm_on; + int bus, tm_enabled, target_role; + target_id_t target; + lun_id_t lun; + + /* + * We only support either a wildcard target/lun or a target ID of zero and a non-wildcard lun + */ + bus = XS_CHANNEL(ccb); + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + if (target != CAM_TARGET_WILDCARD && target != 0) { + ccb->ccb_h.status = CAM_TID_INVALID; + xpt_done(ccb); + return; + } + if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) { + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; + } + + if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; + } + if (isp->isp_dblev & ISP_LOGTDEBUG0) { + xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus); + } + + /* + * Wait until we're not busy with the lun enables subsystem + */ + while (isp->isp_osinfo.tmbusy) { + isp->isp_osinfo.tmwanted = 1; + mtx_sleep(isp, &isp->isp_lock, PRIBIO, "want_isp_enable_lun", 0); + } + isp->isp_osinfo.tmbusy = 1; + + /* + * This is as a good a place as any to check f/w capabilities. + */ + + if (IS_FC(isp)) { + if (ISP_CAP_TMODE(isp) == 0) { + xpt_print(ccb->ccb_h.path, "firmware does not support target mode\n"); + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + goto done; + } + /* + * We *could* handle non-SCCLUN f/w, but we'd have to + * dork with our already fragile enable/disable code. + */ + if (ISP_CAP_SCCFW(isp) == 0) { + xpt_print(ccb->ccb_h.path, "firmware not SCCLUN capable\n"); + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + goto done; + } + + target_role = (FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0; + + } else { + target_role = (SDPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0; + } + + /* + * Create the state pointer. + * It should not already exist. + */ + tptr = get_lun_statep(isp, bus, lun); + if (tptr) { + ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; + goto done; + } + ccb->ccb_h.status = create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); + if (ccb->ccb_h.status != CAM_REQ_CMP) { + goto done; + } + + /* + * We have a tricky maneuver to perform here. + * + * If target mode isn't already enabled here, + * *and* our current role includes target mode, + * we enable target mode here. + * + */ + ISP_GET_PC(isp, bus, tm_enabled, tm_enabled); + if (tm_enabled == 0 && target_role != 0) { + if (isp_enable_target_mode(isp, bus)) { + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + destroy_lun_state(isp, tptr); + tptr = NULL; + goto done; + } + tm_enabled = 1; + } + + /* + * Now check to see whether this bus is in target mode already. + * + * If not, a later role change into target mode will finish the job. + */ + if (tm_enabled == 0) { + ISP_SET_PC(isp, bus, tm_enable_defer, 1); + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_print(ccb->ccb_h.path, "Target Mode Not Enabled Yet- Lun Enables Deferred\n"); + goto done; + } + + /* + * Enable the lun. + */ + ccb->ccb_h.status = isp_enable_deferred(isp, bus, lun); + +done: + if (ccb->ccb_h.status != CAM_REQ_CMP && tptr) { + destroy_lun_state(isp, tptr); + tptr = NULL; + } + if (tptr) { + rls_lun_statep(isp, tptr); + } + isp->isp_osinfo.tmbusy = 0; + if (isp->isp_osinfo.tmwanted) { + isp->isp_osinfo.tmwanted = 0; + wakeup(isp); + } + xpt_done(ccb); +} + +static void +isp_enable_deferred_luns(ispsoftc_t *isp, int bus) +{ + /* + * XXX: not entirely implemented yet + */ + (void) isp_enable_deferred(isp, bus, 0); +} + +static uint32_t +isp_enable_deferred(ispsoftc_t *isp, int bus, lun_id_t lun) +{ + cam_status status; + + isp_prt(isp, ISP_LOGTINFO, "%s: bus %d lun %u", __func__, bus, lun); + if (IS_24XX(isp) || (IS_FC(isp) && ISP_FC_PC(isp, bus)->tm_luns_enabled)) { + status = CAM_REQ_CMP; + } else { + int cmd_cnt, not_cnt; + + if (IS_23XX(isp)) { + cmd_cnt = DFLT_CMND_CNT; + not_cnt = DFLT_INOT_CNT; + } else { + cmd_cnt = 64; + not_cnt = 8; + } + status = CAM_REQ_INPROG; + isp->isp_osinfo.rptr = &status; + if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, DFLT_CMND_CNT, DFLT_INOT_CNT)) { + status = CAM_RESRC_UNAVAIL; + } else { + mtx_sleep(&status, &isp->isp_lock, PRIBIO, "isp_enable_deferred", 0); + } + isp->isp_osinfo.rptr = NULL; + } + + if (status == CAM_REQ_CMP) { + ISP_SET_PC(isp, bus, tm_luns_enabled, 1); + isp_prt(isp, ISP_LOGTINFO, "bus %d lun %u now enabled for target mode", bus, lun); + } + return (status); +} + +static void +isp_disable_lun(ispsoftc_t *isp, union ccb *ccb) +{ + tstate_t *tptr = NULL; + int bus; + cam_status status; + target_id_t target; lun_id_t lun; - target_id_t tgt; bus = XS_CHANNEL(ccb); - if (bus > 1) { - xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus); - ccb->ccb_h.status = CAM_PATH_INVALID; - return (-1); - } - tgt = ccb->ccb_h.target_id; + target = ccb->ccb_h.target_id; lun = ccb->ccb_h.target_lun; - - if (isp->isp_dblev & ISP_LOGTDEBUG0) { - xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n", - cel->enable? "en" : "dis", lun, bus); + if (target != CAM_TARGET_WILDCARD && target != 0) { + ccb->ccb_h.status = CAM_TID_INVALID; + xpt_done(ccb); + return; + } + if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) { + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; } - if ((lun != CAM_LUN_WILDCARD) && - (lun >= (lun_id_t) isp->isp_maxluns)) { + if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { ccb->ccb_h.status = CAM_LUN_INVALID; - return (-1); + xpt_done(ccb); + return; + } + if (isp->isp_dblev & ISP_LOGTDEBUG0) { + xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus); + } + + /* + * See if we're busy disabling a lun now. + */ + while (isp->isp_osinfo.tmbusy) { + isp->isp_osinfo.tmwanted = 1; + mtx_sleep(isp, &isp->isp_lock, PRIBIO, "want_isp_disable_lun", 0); + } + isp->isp_osinfo.tmbusy = 1; + + /* + * Find the state pointer. + */ + if ((tptr = get_lun_statep(isp, bus, lun)) == NULL) { + ccb->ccb_h.status = CAM_PATH_INVALID; + goto done; + } + + /* + * If we're a 24XX card, we're done. + */ + if (IS_24XX(isp)) { + status = CAM_REQ_CMP; + goto done; + } + + /* + * For SCC FW, we only deal with lun zero. + */ + if (IS_FC(isp)) { + lun = 0; + } + + isp->isp_osinfo.rptr = &status; + status = CAM_REQ_INPROG; + if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, 0, 0)) { + status = CAM_RESRC_UNAVAIL; + } else { + mtx_sleep(ccb, &isp->isp_lock, PRIBIO, "isp_disable_lun", 0); + } +done: + if (status == CAM_REQ_CMP) { + xpt_print(ccb->ccb_h.path, "now disabled for target mode\n"); + } + if (tptr) { + rls_lun_statep(isp, tptr); + } + isp->isp_osinfo.rptr = NULL; + isp->isp_osinfo.tmbusy = 0; + if (isp->isp_osinfo.tmwanted) { + isp->isp_osinfo.tmwanted = 0; + wakeup(isp); + } + xpt_done(ccb); +} + +static int +isp_enable_target_mode(ispsoftc_t *isp, int bus) +{ + int ct; + + ISP_GET_PC(isp, bus, tm_enabled, ct); + if (ct != 0) { + return (0); } if (IS_SCSI(isp)) { - sdparam *sdp = isp->isp_param; - sdp += bus; - if (tgt != CAM_TARGET_WILDCARD && - tgt != sdp->isp_initiator_id) { - ccb->ccb_h.status = CAM_TID_INVALID; - return (-1); - } - } else { - /* - * There's really no point in doing this yet w/o multi-tid - * capability. Even then, it's problematic. - */ -#if 0 - if (tgt != CAM_TARGET_WILDCARD && - tgt != FCPARAM(isp)->isp_iid) { - ccb->ccb_h.status = CAM_TID_INVALID; - return (-1); - } -#endif - /* - * This is as a good a place as any to check f/w capabilities. - */ - if (FCPARAM(isp)->isp_tmode == 0) { - xpt_print(ccb->ccb_h.path, - "firmware does not support target mode\n"); - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return (-1); - } - /* - * XXX: We *could* handle non-SCCLUN f/w, but we'd have to - * XXX: dork with our already fragile enable/disable code. - */ - if (FCPARAM(isp)->isp_sccfw == 0) { - xpt_print(ccb->ccb_h.path, - "firmware not SCCLUN capable\n"); - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return (-1); + mbreg_t mbs; + + MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0); + mbs.param[0] = MBOX_ENABLE_TARGET_MODE; + mbs.param[1] = ENABLE_TARGET_FLAG|ENABLE_TQING_FLAG; + mbs.param[2] = bus << 7; + if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "Unable to add Target Role to Bus %d", bus); + return (EIO); } + SDPARAM(isp, bus)->role |= ISP_ROLE_TARGET; } - - if (tgt == CAM_TARGET_WILDCARD) { - if (lun == CAM_LUN_WILDCARD) { - wildcard = 1; - } else { - ccb->ccb_h.status = CAM_LUN_INVALID; - return (-1); - } - } else { - wildcard = 0; - } - - tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0; - - /* - * Next check to see whether this is a target/lun wildcard action. - * - * If so, we know that we can accept commands for luns that haven't - * been enabled yet and send them upstream. Otherwise, we have to - * handle them locally (if we see them at all). - */ - - if (wildcard) { - tptr = &isp->isp_osinfo.tsdflt[bus]; - if (cel->enable) { - if (tm_on) { - ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return (-1); - } - ccb->ccb_h.status = - xpt_create_path(&tptr->owner, NULL, - xpt_path_path_id(ccb->ccb_h.path), - xpt_path_target_id(ccb->ccb_h.path), - xpt_path_lun_id(ccb->ccb_h.path)); - if (ccb->ccb_h.status != CAM_REQ_CMP) { - return (-1); - } - SLIST_INIT(&tptr->atios); - SLIST_INIT(&tptr->inots); - isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED; - } else { - if (tm_on == 0) { - ccb->ccb_h.status = CAM_REQ_CMP; - return (-1); - } - if (tptr->hold) { - ccb->ccb_h.status = CAM_SCSI_BUSY; - return (-1); - } - xpt_free_path(tptr->owner); - isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED; - } - } - - /* - * Now check to see whether this bus needs to be - * enabled/disabled with respect to target mode. - */ - av = bus << 31; - if (cel->enable && tm_on == 0) { - av |= ENABLE_TARGET_FLAG; - av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); - if (av) { - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - if (wildcard) { - isp->isp_osinfo.tmflags[bus] &= - ~TM_WILDCARD_ENABLED; - xpt_free_path(tptr->owner); - } - return (-1); - } - isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED; - xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n"); - } else if (cel->enable == 0 && tm_on && wildcard) { - if (are_any_luns_enabled(isp, bus)) { - ccb->ccb_h.status = CAM_SCSI_BUSY; - return (-1); - } - av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); - if (av) { - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return (-1); - } - isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; - xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n"); - } - - if (wildcard) { - ccb->ccb_h.status = CAM_REQ_CMP; - return (-1); - } - - /* - * Find an empty slot - */ - for (seq = 0; seq < NLEACT; seq++) { - if (isp->isp_osinfo.leact[seq] == 0) { - break; - } - } - if (seq >= NLEACT) { - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return (-1); - - } - isp->isp_osinfo.leact[seq] = ccb; - - if (cel->enable) { - ccb->ccb_h.status = - create_lun_state(isp, bus, ccb->ccb_h.path, &tptr); - if (ccb->ccb_h.status != CAM_REQ_CMP) { - isp->isp_osinfo.leact[seq] = 0; - return (-1); - } - } else { - tptr = get_lun_statep(isp, bus, lun); - if (tptr == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - return (-1); - } - } - - if (cel->enable) { - int c, n, ulun = lun; - - cmd = RQSTYPE_ENABLE_LUN; - c = DFLT_CMND_CNT; - n = DFLT_INOT_CNT; - if (IS_FC(isp) && lun != 0) { - cmd = RQSTYPE_MODIFY_LUN; - n = 0; - /* - * For SCC firmware, we only deal with setting - * (enabling or modifying) lun 0. - */ - ulun = 0; - } - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { - rls_lun_statep(isp, tptr); - ccb->ccb_h.status = CAM_REQ_INPROG; - return (seq); - } - } else { - int c, n, ulun = lun; - - cmd = -RQSTYPE_MODIFY_LUN; - c = DFLT_CMND_CNT; - n = DFLT_INOT_CNT; - if (IS_FC(isp) && lun != 0) { - n = 0; - /* - * For SCC firmware, we only deal with setting - * (enabling or modifying) lun 0. - */ - ulun = 0; - } - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) { - rls_lun_statep(isp, tptr); - ccb->ccb_h.status = CAM_REQ_INPROG; - return (seq); - } - } - rls_lun_statep(isp, tptr); - xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n"); - isp->isp_osinfo.leact[seq] = 0; - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - return (-1); + ISP_SET_PC(isp, bus, tm_enabled, 1); + isp_prt(isp, ISP_LOGINFO, "Target Role added to Bus %d", bus); + return (0); } +#ifdef NEEDED +static int +isp_disable_target_mode(ispsoftc_t *isp, int bus) +{ + int ct; + + ISP_GET_PC(isp, bus, tm_enabled, ct); + if (ct == 0) { + return (0); + } + + if (IS_SCSI(isp)) { + mbreg_t mbs; + + MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0); + mbs.param[2] = bus << 7; + if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "Unable to subtract Target Role to Bus %d", bus); + return (EIO); + } + SDPARAM(isp, bus)->role &= ~ISP_ROLE_TARGET; + } + ISP_SET_PC(isp, bus, tm_enabled, 0); + isp_prt(isp, ISP_LOGINFO, "Target Role subtracted from Bus %d", bus); + return (0); +} +#endif + static void isp_ledone(ispsoftc_t *isp, lun_entry_t *lep) { - const char lfmt[] = "now %sabled for target mode\n"; - union ccb *ccb; - uint32_t seq; - tstate_t *tptr; - int av; - struct ccb_en_lun *cel; - - seq = lep->le_reserved - 1; - if (seq >= NLEACT) { - isp_prt(isp, ISP_LOGERR, - "seq out of range (%u) in isp_ledone", seq); - return; - } - ccb = isp->isp_osinfo.leact[seq]; - if (ccb == 0) { - isp_prt(isp, ISP_LOGERR, - "no ccb for seq %u in isp_ledone", seq); - return; - } - cel = &ccb->cel; - tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); - if (tptr == NULL) { - xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n"); - isp->isp_osinfo.leact[seq] = 0; - return; - } + uint32_t *rptr; + rptr = isp->isp_osinfo.rptr; if (lep->le_status != LUN_OK) { - xpt_print(ccb->ccb_h.path, - "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status); -err: - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - rls_lun_statep(isp, tptr); - isp->isp_osinfo.leact[seq] = 0; - xpt_done(ccb); - return; + isp_prt(isp, ISP_LOGERR, "ENABLE/MODIFY LUN returned 0x%x", lep->le_status); + if (rptr) { + *rptr = CAM_REQ_CMP_ERR; + wakeup_one(rptr); + } } else { - isp_prt(isp, ISP_LOGTDEBUG0, - "isp_ledone: ENABLE/MODIFY done okay"); - } - - - if (cel->enable) { - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print(ccb->ccb_h.path, lfmt, "en"); - rls_lun_statep(isp, tptr); - isp->isp_osinfo.leact[seq] = 0; - xpt_done(ccb); - return; - } - - if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) { - if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb), - XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) { - xpt_print(ccb->ccb_h.path, - "isp_ledone: isp_lun_cmd failed\n"); - goto err; - } - rls_lun_statep(isp, tptr); - return; - } - - xpt_print(ccb->ccb_h.path, lfmt, "dis"); - rls_lun_statep(isp, tptr); - destroy_lun_state(isp, tptr); - ccb->ccb_h.status = CAM_REQ_CMP; - isp->isp_osinfo.leact[seq] = 0; - xpt_done(ccb); - if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) { - int bus = XS_CHANNEL(ccb); - av = bus << 31; - av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); - if (av) { - isp_prt(isp, ISP_LOGWARN, - "disable target mode on channel %d failed", bus); - } - isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED; - } -} - - -static cam_status -isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb) -{ - tstate_t *tptr; - struct ccb_hdr_slist *lp; - struct ccb_hdr *curelm; - int found, *ctr; - union ccb *accb = ccb->cab.abort_ccb; - - xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb); - if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - int badpath = 0; - if (IS_FC(isp) && (accb->ccb_h.target_id != - ((fcparam *) isp->isp_param)->isp_loopid)) { - badpath = 1; - } else if (IS_SCSI(isp) && (accb->ccb_h.target_id != - ((sdparam *) isp->isp_param)->isp_initiator_id)) { - badpath = 1; - } - if (badpath) { - /* - * Being restrictive about target ids is really about - * making sure we're aborting for the right multi-tid - * path. This doesn't really make much sense at present. - */ -#if 0 - return (CAM_PATH_INVALID); -#endif + if (rptr) { + *rptr = CAM_REQ_CMP; + wakeup_one(rptr); } } - tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun); - if (tptr == NULL) { - xpt_print(ccb->ccb_h.path, "can't get statep\n"); - return (CAM_PATH_INVALID); - } - if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { - lp = &tptr->atios; - ctr = &tptr->atio_count; - } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { - lp = &tptr->inots; - ctr = &tptr->inot_count; - } else { - rls_lun_statep(isp, tptr); - xpt_print(ccb->ccb_h.path, "bad function code %d\n", - accb->ccb_h.func_code); - return (CAM_UA_ABORT); - } - curelm = SLIST_FIRST(lp); - found = 0; - if (curelm == &accb->ccb_h) { - found = 1; - SLIST_REMOVE_HEAD(lp, sim_links.sle); - } else { - while(curelm != NULL) { - struct ccb_hdr *nextelm; - - nextelm = SLIST_NEXT(curelm, sim_links.sle); - if (nextelm == &accb->ccb_h) { - found = 1; - SLIST_NEXT(curelm, sim_links.sle) = - SLIST_NEXT(nextelm, sim_links.sle); - break; - } - curelm = nextelm; - } - } - rls_lun_statep(isp, tptr); - if (found) { - (*ctr)--; - accb->ccb_h.status = CAM_REQ_ABORTED; - xpt_done(accb); - return (CAM_REQ_CMP); - } - xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb); - return (CAM_PATH_INVALID); } static void isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) { void *qe; + tstate_t *tptr; + atio_private_data_t *atp; struct ccb_scsiio *cso = &ccb->csio; - uint32_t nxti, optr, handle; + uint32_t dmaresult, handle; uint8_t local[QENTRY_LEN]; + /* + * Do some sanity checks. + */ + if (cso->dxfer_len == 0) { + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { + xpt_print(ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } + } - if (isp_getrqentry(isp, &nxti, &optr, &qe)) { - xpt_print(ccb->ccb_h.path, - "Request Queue Overflow in isp_target_start_ctio\n"); - XS_SETERR(ccb, CAM_REQUEUE_REQ); + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); + if (tptr == NULL) { + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD); + if (tptr == NULL) { + xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find tstate pointer in %s\n", __func__, cso->tag_id); + dump_tstates(isp, XS_CHANNEL(ccb)); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + xpt_done(ccb); + return; + } + } + + atp = isp_get_atpd(isp, tptr, cso->tag_id); + if (atp == NULL) { + xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find private data adjunct\n", __func__, cso->tag_id); + isp_dump_atpd(isp, tptr); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + xpt_done(ccb); + return; + } + if (atp->dead) { + xpt_print(ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO for a dead command\n", __func__, cso->tag_id); + ccb->ccb_h.status = CAM_REQ_ABORTED; + xpt_done(ccb); + return; + } + + /* + * Check to make sure we're still in target mode. + */ + if ((FCPARAM(isp, XS_CHANNEL(ccb))->role & ISP_ROLE_TARGET) == 0) { + xpt_print(ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO because we're no longer in target mode\n", __func__, cso->tag_id); + ccb->ccb_h.status = CAM_PROVIDE_FAIL; + xpt_done(ccb); + return; + } + + /* + * Get some resources + */ + if (isp_get_pcmd(isp, ccb)) { + rls_lun_statep(isp, tptr); + xpt_print(ccb->ccb_h.path, "out of PCMDs\n"); + cam_freeze_devq(ccb->ccb_h.path); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); + ccb->ccb_h.status = CAM_REQUEUE_REQ; + xpt_done(ccb); + return; + } + qe = isp_getrqentry(isp); + if (qe == NULL) { + xpt_print(ccb->ccb_h.path, rqo, __func__); + cam_freeze_devq(ccb->ccb_h.path); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); + ccb->ccb_h.status = CAM_REQUEUE_REQ; goto out; } memset(local, 0, QENTRY_LEN); @@ -1218,53 +1458,102 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) /* * We're either moving data or completing a command here. */ + if (IS_24XX(isp)) { + ct7_entry_t *cto = (ct7_entry_t *) local; - if (IS_FC(isp)) { - atio_private_data_t *atp; + cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + cto->ct_header.rqs_entry_count = 1; + cto->ct_header.rqs_seqno = 1; + cto->ct_nphdl = atp->nphdl; + cto->ct_rxid = atp->tag; + cto->ct_iid_lo = atp->portid; + cto->ct_iid_hi = atp->portid >> 16; + cto->ct_oxid = atp->oxid; + cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb)); + cto->ct_scsi_status = cso->scsi_status; + cto->ct_timeout = 120; + cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT; + if (ccb->ccb_h.flags & CAM_SEND_STATUS) { + cto->ct_flags |= CT7_SENDSTATUS; + } + if (cso->dxfer_len == 0) { + cto->ct_flags |= CT7_FLAG_MODE1 | CT7_NO_DATA; + if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { + int m = min(cso->sense_len, sizeof (struct scsi_sense_data)); + cto->rsp.m1.ct_resplen = cto->ct_senselen = min(m, MAXRESPLEN_24XX); + memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, cto->ct_senselen); + cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); + } + } else { + cto->ct_flags |= CT7_FLAG_MODE0; + if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + cto->ct_flags |= CT7_DATA_IN; + } else { + cto->ct_flags |= CT7_DATA_OUT; + } + cto->rsp.m0.reloff = atp->bytes_xfered; + /* + * Don't overrun the limits placed on us + */ + if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) { + cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered; + } + atp->last_xframt = cso->dxfer_len; + cto->rsp.m0.ct_xfrlen = cso->dxfer_len; + } + if (cto->ct_flags & CT7_SENDSTATUS) { + int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0; + cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len); + if (cto->ct_resid < 0) { + cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8); + } else if (cto->ct_resid > 0) { + cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8); + } + atp->state = ATPD_STATE_LAST_CTIO; + ISP_PATH_PRT(isp, lvl, cso->ccb_h.path, "%s: CTIO7[%x] CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u\n", __func__, cto->ct_rxid, + atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered); + } else { + cto->ct_resid = 0; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, cso->ccb_h.path, "%s: CTIO7[%x] flags %x xfrlen %u offset %u\n", __func__, cto->ct_rxid, cto->ct_flags, + cso->dxfer_len, atp->bytes_xfered); + atp->state = ATPD_STATE_CTIO; + } + } else if (IS_FC(isp)) { ct2_entry_t *cto = (ct2_entry_t *) local; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; cto->ct_header.rqs_entry_count = 1; - if (FCPARAM(isp)->isp_2klogin) { + cto->ct_header.rqs_seqno = 1; + if (ISP_CAP_2KLOGIN(isp) == 0) { ((ct2e_entry_t *)cto)->ct_iid = cso->init_id; } else { cto->ct_iid = cso->init_id; - if (FCPARAM(isp)->isp_sccfw == 0) { + if (ISP_CAP_SCCFW(isp) == 0) { cto->ct_lun = ccb->ccb_h.target_lun; } } - atp = isp_get_atpd(isp, cso->tag_id); - if (atp == NULL) { - xpt_print(ccb->ccb_h.path, - "cannot find private data adjunct for tag %x\n", - cso->tag_id); - XS_SETERR(ccb, CAM_REQ_CMP_ERR); - goto out; - } cto->ct_rxid = cso->tag_id; if (cso->dxfer_len == 0) { - cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; - if (ccb->ccb_h.flags & CAM_SEND_STATUS) { - cto->ct_flags |= CT2_SENDSTATUS; - cto->rsp.m1.ct_scsi_status = cso->scsi_status; - cto->ct_resid = - atp->orig_datalen - atp->bytes_xfered; - if (cto->ct_resid < 0) { - cto->rsp.m1.ct_scsi_status |= - CT2_DATA_OVER; - } else if (cto->ct_resid > 0) { - cto->rsp.m1.ct_scsi_status |= - CT2_DATA_UNDER; - } + cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA | CT2_SENDSTATUS; + cto->rsp.m1.ct_scsi_status = cso->scsi_status; + cto->ct_resid = atp->orig_datalen - atp->bytes_xfered; + if (cto->ct_resid < 0) { + cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER; + } else if (cto->ct_resid > 0) { + cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER; } if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) { int m = min(cso->sense_len, MAXRESPLEN); - memcpy(cto->rsp.m1.ct_resp, - &cso->sense_data, m); + memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, m); cto->rsp.m1.ct_senselen = m; cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; + } else if (cso->scsi_status == SCSI_STATUS_CHECK_COND) { + /* + * XXX: DEBUG + */ + xpt_print(ccb->ccb_h.path, "CHECK CONDITION being sent without associated SENSE DATA for CDB=0x%x\n", atp->cdb0); } } else { cto->ct_flags |= CT2_FLAG_MODE0; @@ -1274,18 +1563,21 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) cto->ct_flags |= CT2_DATA_OUT; } cto->ct_reloff = atp->bytes_xfered; + cto->rsp.m0.ct_xfrlen = cso->dxfer_len; + /* + * Don't overrun the limits placed on us + */ + if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) { + cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered; + } if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { cto->ct_flags |= CT2_SENDSTATUS; cto->rsp.m0.ct_scsi_status = cso->scsi_status; - cto->ct_resid = - atp->orig_datalen - - (atp->bytes_xfered + cso->dxfer_len); + cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len); if (cto->ct_resid < 0) { - cto->rsp.m0.ct_scsi_status |= - CT2_DATA_OVER; + cto->rsp.m0.ct_scsi_status |= CT2_DATA_OVER; } else if (cto->ct_resid > 0) { - cto->rsp.m0.ct_scsi_status |= - CT2_DATA_UNDER; + cto->rsp.m0.ct_scsi_status |= CT2_DATA_UNDER; } } else { atp->last_xframt = cso->dxfer_len; @@ -1298,14 +1590,16 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) } if (cto->ct_flags & CT2_SENDSTATUS) { - isp_prt(isp, ISP_LOGTDEBUG0, - "CTIO2[%x] STATUS %x origd %u curd %u resid %u", - cto->ct_rxid, cso->scsi_status, atp->orig_datalen, - cso->dxfer_len, cto->ct_resid); + int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0; cto->ct_flags |= CT2_CCINCR; atp->state = ATPD_STATE_LAST_CTIO; + ISP_PATH_PRT(isp, lvl, cso->ccb_h.path, "%s: CTIO2[%x] CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u\n", __func__, cto->ct_rxid, + atp->cdb0, cto->rsp.m0.ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered); } else { + cto->ct_resid = 0; atp->state = ATPD_STATE_CTIO; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: CTIO2[%x] flags %x xfrlen %u offset %u\n", __func__, cto->ct_rxid, cto->ct_flags, + cso->dxfer_len, atp->bytes_xfered); } cto->ct_timeout = 10; } else { @@ -1313,13 +1607,14 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_count = 1; + cto->ct_header.rqs_seqno = 1; cto->ct_iid = cso->init_id; cto->ct_iid |= XS_CHANNEL(ccb) << 7; cto->ct_tgt = ccb->ccb_h.target_id; cto->ct_lun = ccb->ccb_h.target_lun; - cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id); + cto->ct_fwhandle = cso->tag_id >> 16; if (AT_HAS_TAG(cso->tag_id)) { - cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id); + cto->ct_tag_val = cso->tag_id; cto->ct_flags |= CT_TQAE; } if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { @@ -1336,19 +1631,16 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR; cto->ct_scsi_status = cso->scsi_status; cto->ct_resid = cso->resid; - isp_prt(isp, ISP_LOGTDEBUG0, - "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x", - cto->ct_fwhandle, cso->scsi_status, cso->resid, - cso->tag_id); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: CTIO[%x] scsi status %x resid %d tag_id %x\n", __func__, + cto->ct_fwhandle, cso->scsi_status, cso->resid, cso->tag_id); } ccb->ccb_h.flags &= ~CAM_SEND_SENSE; cto->ct_timeout = 10; } if (isp_save_xs_tgt(isp, ccb, &handle)) { - xpt_print(ccb->ccb_h.path, - "No XFLIST pointers for isp_target_start_ctio\n"); - XS_SETERR(ccb, CAM_REQUEUE_REQ); + xpt_print(ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__); + ccb->ccb_h.status = CAM_REQUEUE_REQ; goto out; } @@ -1362,7 +1654,10 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) * format. */ - if (IS_FC(isp)) { + if (IS_24XX(isp)) { + ct7_entry_t *cto = (ct7_entry_t *) local; + cto->ct_syshandle = handle; + } else if (IS_FC(isp)) { ct2_entry_t *cto = (ct2_entry_t *) local; cto->ct_syshandle = handle; } else { @@ -1370,31 +1665,33 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb) cto->ct_syshandle = handle; } - switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) { - case CMD_QUEUED: - ISP_ADD_REQUEST(isp, nxti); + dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local); + if (dmaresult == CMD_QUEUED) { + isp->isp_nactive++; ccb->ccb_h.status |= CAM_SIM_QUEUED; + rls_lun_statep(isp, tptr); return; - - case CMD_EAGAIN: - XS_SETERR(ccb, CAM_REQUEUE_REQ); - break; - - default: - break; + } + if (dmaresult == CMD_EAGAIN) { + ccb->ccb_h.status = CAM_REQUEUE_REQ; + } else { + ccb->ccb_h.status = CAM_REQ_CMP_ERR; } isp_destroy_tgt_handle(isp, handle); - out: + rls_lun_statep(isp, tptr); + isp_free_pcmd(isp, ccb); xpt_done(ccb); } static void isp_refire_putback_atio(void *arg) { - int s = splcam(); - isp_target_putback_atio(arg); - splx(s); + union ccb *ccb = arg; + ispsoftc_t *isp = XS_ISP(ccb); + ISP_LOCK(isp); + isp_target_putback_atio(ccb); + ISP_UNLOCK(isp); } static void @@ -1402,14 +1699,13 @@ isp_target_putback_atio(union ccb *ccb) { ispsoftc_t *isp; struct ccb_scsiio *cso; - uint32_t nxti, optr; void *qe; isp = XS_ISP(ccb); - if (isp_getrqentry(isp, &nxti, &optr, &qe)) { - xpt_print(ccb->ccb_h.path, - "isp_target_putback_atio: Request Queue Overflow\n"); + qe = isp_getrqentry(isp); + if (qe == NULL) { + xpt_print(ccb->ccb_h.path, rqo, __func__); (void) timeout(isp_refire_putback_atio, ccb, 10); return; } @@ -1417,10 +1713,10 @@ isp_target_putback_atio(union ccb *ccb) cso = &ccb->csio; if (IS_FC(isp)) { at2_entry_t local, *at = &local; - MEMZERO(at, sizeof (at2_entry_t)); + ISP_MEMZERO(at, sizeof (at2_entry_t)); at->at_header.rqs_entry_type = RQSTYPE_ATIO2; at->at_header.rqs_entry_count = 1; - if (FCPARAM(isp)->isp_sccfw) { + if (ISP_CAP_SCCFW(isp)) { at->at_scclun = (uint16_t) ccb->ccb_h.target_lun; } else { at->at_lun = (uint8_t) ccb->ccb_h.target_lun; @@ -1431,7 +1727,7 @@ isp_target_putback_atio(union ccb *ccb) isp_put_atio2(isp, at, qe); } else { at_entry_t local, *at = &local; - MEMZERO(at, sizeof (at_entry_t)); + ISP_MEMZERO(at, sizeof (at_entry_t)); at->at_header.rqs_entry_type = RQSTYPE_ATIO; at->at_header.rqs_entry_count = 1; at->at_iid = cso->init_id; @@ -1443,8 +1739,8 @@ isp_target_putback_atio(union ccb *ccb) at->at_handle = AT_GET_HANDLE(cso->tag_id); isp_put_atio(isp, at, qe); } - ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe); + ISP_SYNC_REQUEST(isp); isp_complete_ctio(ccb); } @@ -1455,6 +1751,7 @@ isp_complete_ctio(union ccb *ccb) ccb->ccb_h.status |= CAM_REQ_CMP; } ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + isp_free_pcmd(XS_ISP(ccb), ccb); xpt_done(ccb); } @@ -1463,12 +1760,13 @@ isp_complete_ctio(union ccb *ccb) * This means handling CDBs. */ -static int +static void isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) { tstate_t *tptr; - int status, bus, iswildcard; + int status, bus; struct ccb_accept_tio *atiop; + atio_private_data_t *atp; /* * The firmware status (except for the QLTM_SVALID bit) @@ -1488,13 +1786,12 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) */ isp_prt(isp, ISP_LOGWARN, "PHASE ERROR"); isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); - return (0); + return; } if ((status & ~QLTM_SVALID) != AT_CDB) { - isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", - status); + isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", status); isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); - return (0); + return; } bus = GET_BUS_VAL(aep->at_iid); @@ -1512,15 +1809,13 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) * blackhole driver, so they get what they deserve. */ isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); - return (0); + return; } - iswildcard = 1; - } else { - iswildcard = 0; } + atp = isp_get_atpd(isp, tptr, 0); atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); - if (atiop == NULL) { + if (atiop == NULL || atp == NULL) { /* * Because we can't autofeed sense data back with * a command for parallel SCSI, we can't give back @@ -1529,24 +1824,25 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) * should, in fact, get this, is in the case that we've * run out of ATIOS. */ - xpt_print(tptr->owner, - "no ATIOS for lun %d from initiator %d on channel %d\n", - aep->at_lun, GET_IID_VAL(aep->at_iid), bus); - if (aep->at_flags & AT_TQAE) - isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); - else - isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); + xpt_print(tptr->owner, "no %s for lun %d from initiator %d\n", (atp == NULL && atiop == NULL)? "ATIOs *or* ATPS" : + ((atp == NULL)? "ATPs" : "ATIOs"), aep->at_lun, aep->at_iid); + isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); + if (atp) { + isp_put_atpd(isp, tptr, atp); + } rls_lun_statep(isp, tptr); - return (0); + return; } + atp->tag = aep->at_tag_val; + if (atp->tag == 0) { + atp->tag = ~0; + } + atp->state = ATPD_STATE_ATIO; SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); tptr->atio_count--; - isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", - aep->at_lun, tptr->atio_count); - if (iswildcard) { - atiop->ccb_h.target_id = aep->at_tgt; - atiop->ccb_h.target_lun = aep->at_lun; - } + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count); + atiop->ccb_h.target_id = aep->at_tgt; + atiop->ccb_h.target_lun = aep->at_lun; if (aep->at_flags & AT_NODISC) { atiop->ccb_h.flags = CAM_DIS_DISCONNECT; } else { @@ -1556,42 +1852,48 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) if (status & QLTM_SVALID) { size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data)); atiop->sense_len = amt; - MEMCPY(&atiop->sense_data, aep->at_sense, amt); + ISP_MEMCPY(&atiop->sense_data, aep->at_sense, amt); } else { atiop->sense_len = 0; } atiop->init_id = GET_IID_VAL(aep->at_iid); atiop->cdb_len = aep->at_cdblen; - MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); + ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); atiop->ccb_h.status = CAM_CDB_RECVD; /* * Construct a tag 'id' based upon tag value (which may be 0..255) * and the handle (which we have to preserve). */ - AT_MAKE_TAGID(atiop->tag_id, bus, device_get_unit(isp->isp_dev), aep); + atiop->tag_id = atp->tag; if (aep->at_flags & AT_TQAE) { atiop->tag_action = aep->at_tag_type; atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; } - xpt_done((union ccb*)atiop); - isp_prt(isp, ISP_LOGTDEBUG0, - "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", - aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), - GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, - aep->at_tag_type, (aep->at_flags & AT_NODISC)? - "nondisc" : "disconnecting"); + atp->orig_datalen = 0; + atp->bytes_xfered = 0; + atp->last_xframt = 0; + atp->lun = aep->at_lun; + atp->nphdl = aep->at_iid; + atp->portid = PORT_NONE; + atp->oxid = 0; + atp->cdb0 = atiop->cdb_io.cdb_bytes[0]; + atp->tattr = aep->at_tag_type; + atp->state = ATPD_STATE_CAM; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO[%x] CDB=0x%x lun %d\n", aep->at_tag_val, atp->cdb0, atp->lun); rls_lun_statep(isp, tptr); - return (0); } -static int +static void isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) { lun_id_t lun; + fcportdb_t *lp; tstate_t *tptr; struct ccb_accept_tio *atiop; - atio_private_data_t *atp; + uint16_t nphdl; + atio_private_data_t *atp = NULL; + inot_private_data_t *ntp; /* * The firmware status (except for the QLTM_SVALID bit) @@ -1600,127 +1902,457 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) * If QLTM_SVALID is set, the firware has recommended Sense Data. */ if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { - isp_prt(isp, ISP_LOGWARN, - "bogus atio (0x%x) leaked to platform", aep->at_status); + isp_prt(isp, ISP_LOGWARN, "bogus atio (0x%x) leaked to platform", aep->at_status); isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0); - return (0); + return; } - if (FCPARAM(isp)->isp_sccfw) { + if (ISP_CAP_SCCFW(isp)) { lun = aep->at_scclun; } else { lun = aep->at_lun; } + if (ISP_CAP_2KLOGIN(isp)) { + nphdl = ((at2e_entry_t *)aep)->at_iid; + } else { + nphdl = aep->at_iid; + } tptr = get_lun_statep(isp, 0, lun); if (tptr == NULL) { - isp_prt(isp, ISP_LOGTDEBUG0, - "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); if (tptr == NULL) { - isp_endcmd(isp, aep, - SCSI_STATUS_CHECK_COND | ECMD_SVALID | - (0x5 << 12) | (0x25 << 16), 0); - return (0); + isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d", aep->at_rxid, lun); + isp_endcmd(isp, aep, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0); + return; } } - atp = isp_get_atpd(isp, 0); - atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); - if (atiop == NULL || atp == NULL) { - - /* - * Because we can't autofeed sense data back with - * a command for parallel SCSI, we can't give back - * a CHECK CONDITION. We'll give back a QUEUE FULL status - * instead. This works out okay because the only time we - * should, in fact, get this, is in the case that we've - * run out of ATIOS. - */ - xpt_print(tptr->owner, - "no %s for lun %d from initiator %d\n", - (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" : - ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid); - rls_lun_statep(isp, tptr); - isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); - return (0); + /* + * Start any commands pending resources first. + */ + if (tptr->restart_queue) { + inot_private_data_t *restart_queue = tptr->restart_queue; + tptr->restart_queue = NULL; + while (restart_queue) { + ntp = restart_queue; + restart_queue = ntp->rd.nt.nt_hba; + isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid); + isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data); + isp_put_ntpd(isp, tptr, ntp); + /* + * If a recursion caused the restart queue to start to fill again, + * stop and splice the new list on top of the old list and restore + * it and go to noresrc. + */ + if (tptr->restart_queue) { + ntp = tptr->restart_queue; + tptr->restart_queue = restart_queue; + while (restart_queue->rd.nt.nt_hba) { + restart_queue = restart_queue->rd.nt.nt_hba; + } + restart_queue->rd.nt.nt_hba = ntp; + goto noresrc; + } + } } + + atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); + if (atiop == NULL) { + goto noresrc; + } + + atp = isp_get_atpd(isp, tptr, 0); + if (atp == NULL) { + goto noresrc; + } + + atp->tag = aep->at_rxid; atp->state = ATPD_STATE_ATIO; SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); tptr->atio_count--; - isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d", - lun, tptr->atio_count); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count); + atiop->ccb_h.target_id = FCPARAM(isp, 0)->isp_loopid; + atiop->ccb_h.target_lun = lun; - if (tptr == &isp->isp_osinfo.tsdflt[0]) { - atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid; - atiop->ccb_h.target_lun = lun; - } /* * We don't get 'suggested' sense data as we do with SCSI cards. */ atiop->sense_len = 0; + if (ISP_CAP_2KLOGIN(isp)) { + /* + * NB: We could not possibly have 2K logins if we + * NB: also did not have SCC FW. + */ + atiop->init_id = ((at2e_entry_t *)aep)->at_iid; + } else { + atiop->init_id = aep->at_iid; + } - atiop->init_id = aep->at_iid; + /* + * If we're not in the port database, add ourselves. + */ + if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) { + uint64_t iid = + (((uint64_t) aep->at_wwpn[0]) << 48) | + (((uint64_t) aep->at_wwpn[1]) << 32) | + (((uint64_t) aep->at_wwpn[2]) << 16) | + (((uint64_t) aep->at_wwpn[3]) << 0); + /* + * However, make sure we delete ourselves if otherwise + * we were there but at a different loop id. + */ + if (isp_find_pdb_by_wwn(isp, 0, iid, &lp)) { + isp_del_wwn_entry(isp, 0, iid, lp->handle, lp->portid); + } + isp_add_wwn_entry(isp, 0, iid, atiop->init_id, PORT_ANY); + } atiop->cdb_len = ATIO2_CDBLEN; - MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); + ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN); atiop->ccb_h.status = CAM_CDB_RECVD; - atiop->tag_id = aep->at_rxid; + atiop->tag_id = atp->tag; switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { case ATIO2_TC_ATTR_SIMPLEQ: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; atiop->tag_action = MSG_SIMPLE_Q_TAG; break; - case ATIO2_TC_ATTR_HEADOFQ: + case ATIO2_TC_ATTR_HEADOFQ: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; atiop->tag_action = MSG_HEAD_OF_Q_TAG; break; - case ATIO2_TC_ATTR_ORDERED: + case ATIO2_TC_ATTR_ORDERED: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; atiop->tag_action = MSG_ORDERED_Q_TAG; break; - case ATIO2_TC_ATTR_ACAQ: /* ?? */ + case ATIO2_TC_ATTR_ACAQ: /* ?? */ case ATIO2_TC_ATTR_UNTAGGED: default: atiop->tag_action = 0; break; } - atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; - atp->tag = atiop->tag_id; - atp->lun = lun; atp->orig_datalen = aep->at_datalen; - atp->last_xframt = 0; atp->bytes_xfered = 0; + atp->last_xframt = 0; + atp->lun = lun; + atp->nphdl = atiop->init_id; + atp->sid = PORT_ANY; + atp->oxid = aep->at_oxid; + atp->cdb0 = aep->at_cdb[0]; + atp->tattr = aep->at_taskflags & ATIO2_TC_ATTR_MASK; atp->state = ATPD_STATE_CAM; - xpt_done((union ccb*)atiop); - - isp_prt(isp, ISP_LOGTDEBUG0, - "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", - aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, - lun, aep->at_taskflags, aep->at_datalen); + xpt_done((union ccb *)atiop); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO2[%x] CDB=0x%x lun %d datalen %u\n", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen); + rls_lun_statep(isp, tptr); + return; +noresrc: + if (atp) { + isp_put_atpd(isp, tptr, atp); + } + ntp = isp_get_ntpd(isp, tptr); + if (ntp == NULL) { + rls_lun_statep(isp, tptr); + isp_endcmd(isp, aep, nphdl, 0, SCSI_STATUS_BUSY, 0); + return; + } + memcpy(ntp->rd.data, aep, QENTRY_LEN); + ntp->rd.nt.nt_hba = tptr->restart_queue; + tptr->restart_queue = ntp; rls_lun_statep(isp, tptr); - return (0); } -static int +static void +isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) +{ + int cdbxlen; + uint16_t lun, chan, nphdl = NIL_HANDLE; + uint32_t did, sid; + uint64_t wwn = INI_NONE; + fcportdb_t *lp; + tstate_t *tptr; + struct ccb_accept_tio *atiop; + atio_private_data_t *atp = NULL; + inot_private_data_t *ntp; + + did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2]; + sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; + lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | aep->at_cmnd.fcp_cmnd_lun[1]; + + /* + * Find the N-port handle, and Virtual Port Index for this command. + * + * If we can't, we're somewhat in trouble because we can't actually respond w/o that information. + * We also, as a matter of course, need to know the WWN of the initiator too. + */ + if (ISP_CAP_MULTI_ID(isp)) { + /* + * Find the right channel based upon D_ID + */ + isp_find_chan_by_did(isp, did, &chan); + + if (chan == ISP_NOCHAN) { + NANOTIME_T now; + + /* + * If we don't recognizer our own D_DID, terminate the exchange, unless we're within 2 seconds of startup + * It's a bit tricky here as we need to stash this command *somewhere*. + */ + GET_NANOTIME(&now); + if (NANOTIME_SUB(&isp->isp_init_time, &now) > 2000000000ULL) { + isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- dropping", __func__, aep->at_rxid, did); + isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0); + return; + } + tptr = get_lun_statep(isp, 0, 0); + if (tptr == NULL) { + tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); + if (tptr == NULL) { + isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel and no tptr- dropping", __func__, aep->at_rxid, did); + isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0); + return; + } + } + isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- deferring", __func__, aep->at_rxid, did); + goto noresrc; + } + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x", __func__, aep->at_rxid, did, chan, sid); + } else { + chan = 0; + } + + /* + * Find the PDB entry for this initiator + */ + if (isp_find_pdb_by_sid(isp, chan, sid, &lp) == 0) { + /* + * If we're not in the port database terminate the exchange. + */ + isp_prt(isp, ISP_LOGTINFO, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x wasn't in PDB already", + __func__, aep->at_rxid, did, chan, sid); + isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0); + return; + } + nphdl = lp->handle; + wwn = lp->port_wwn; + + /* + * Get the tstate pointer + */ + tptr = get_lun_statep(isp, chan, lun); + if (tptr == NULL) { + tptr = get_lun_statep(isp, chan, CAM_LUN_WILDCARD); + if (tptr == NULL) { + isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d or wildcard", aep->at_rxid, lun); + isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0); + return; + } + } + + /* + * Start any commands pending resources first. + */ + if (tptr->restart_queue) { + inot_private_data_t *restart_queue = tptr->restart_queue; + tptr->restart_queue = NULL; + while (restart_queue) { + ntp = restart_queue; + restart_queue = ntp->rd.nt.nt_hba; + isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid); + isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data); + isp_put_ntpd(isp, tptr, ntp); + /* + * If a recursion caused the restart queue to start to fill again, + * stop and splice the new list on top of the old list and restore + * it and go to noresrc. + */ + if (tptr->restart_queue) { + if (restart_queue) { + ntp = tptr->restart_queue; + tptr->restart_queue = restart_queue; + while (restart_queue->rd.nt.nt_hba) { + restart_queue = restart_queue->rd.nt.nt_hba; + } + restart_queue->rd.nt.nt_hba = ntp; + } + goto noresrc; + } + } + } + + /* + * If the f/w is out of resources, just send a BUSY status back. + */ + if (aep->at_rxid == AT7_NORESRC_RXID) { + rls_lun_statep(isp, tptr); + isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); + return; + } + + /* + * If we're out of resources, just send a BUSY status back. + */ + atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios); + if (atiop == NULL) { + isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atios", aep->at_rxid); + goto noresrc; + } + + atp = isp_get_atpd(isp, tptr, 0); + if (atp == NULL) { + isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid); + goto noresrc; + } + if (isp_get_atpd(isp, tptr, aep->at_rxid)) { + isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] tag wraparound in isp_handle_platforms_atio7 (N-Port Handle 0x%04x S_ID 0x%04x OX_ID 0x%04x)\n", + aep->at_rxid, nphdl, sid, aep->at_hdr.ox_id); + /* + * It's not a "no resource" condition- but we can treat it like one + */ + goto noresrc; + } + + atp->tag = aep->at_rxid; + atp->state = ATPD_STATE_ATIO; + SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); + tptr->atio_count--; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count); + atiop->init_id = nphdl; + atiop->ccb_h.target_id = FCPARAM(isp, chan)->isp_loopid; + atiop->ccb_h.target_lun = lun; + atiop->sense_len = 0; + cdbxlen = aep->at_cmnd.fcp_cmnd_alen_datadir >> FCP_CMND_ADDTL_CDBLEN_SHIFT; + if (cdbxlen) { + isp_prt(isp, ISP_LOGWARN, "additional CDBLEN ignored"); + } + cdbxlen = sizeof (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb); + ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb, cdbxlen); + atiop->cdb_len = cdbxlen; + atiop->ccb_h.status = CAM_CDB_RECVD; + atiop->tag_id = atp->tag; + switch (aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK) { + case FCP_CMND_TASK_ATTR_SIMPLE: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; + atiop->tag_action = MSG_SIMPLE_Q_TAG; + break; + case FCP_CMND_TASK_ATTR_HEAD: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; + atiop->tag_action = MSG_HEAD_OF_Q_TAG; + break; + case FCP_CMND_TASK_ATTR_ORDERED: + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; + atiop->tag_action = MSG_ORDERED_Q_TAG; + break; + default: + /* FALLTHROUGH */ + case FCP_CMND_TASK_ATTR_ACA: + case FCP_CMND_TASK_ATTR_UNTAGGED: + atiop->tag_action = 0; + break; + } + atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl; + atp->bytes_xfered = 0; + atp->last_xframt = 0; + atp->lun = lun; + atp->nphdl = nphdl; + atp->portid = sid; + atp->oxid = aep->at_hdr.ox_id; + atp->cdb0 = atiop->cdb_io.cdb_bytes[0]; + atp->tattr = aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK; + atp->state = ATPD_STATE_CAM; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO7[%x] CDB=0x%x lun %d datalen %u\n", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen); + xpt_done((union ccb *)atiop); + rls_lun_statep(isp, tptr); + return; +noresrc: + if (atp) { + isp_put_atpd(isp, tptr, atp); + } + ntp = isp_get_ntpd(isp, tptr); + if (ntp == NULL) { + rls_lun_statep(isp, tptr); + isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_BUSY, 0); + return; + } + memcpy(ntp->rd.data, aep, QENTRY_LEN); + ntp->rd.nt.nt_hba = tptr->restart_queue; + tptr->restart_queue = ntp; + rls_lun_statep(isp, tptr); +} + +static void isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) { union ccb *ccb; int sentstatus, ok, notify_cam, resid = 0; - uint16_t tval; + tstate_t *tptr = NULL; + atio_private_data_t *atp = NULL; + int bus; + uint32_t tval, handle; /* - * CTIO and CTIO2 are close enough.... + * CTIO, CTIO2 and CTIO7 are close enough.... */ - ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); - KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio")); - isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); + if (IS_SCSI(isp)) { + handle = ((ct_entry_t *)arg)->ct_syshandle; + } else { + handle = ((ct2_entry_t *)arg)->ct_syshandle; + } + ccb = isp_find_xs_tgt(isp, handle); + if (ccb == NULL) { + isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg); + return; + } + isp_destroy_tgt_handle(isp, handle); + bus = XS_CHANNEL(ccb); + tptr = get_lun_statep(isp, bus, XS_LUN(ccb)); + if (tptr == NULL) { + tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD); + } + KASSERT((tptr != NULL), ("cannot get state pointer")); + if (isp->isp_nactive) { + isp->isp_nactive++; + } + if (IS_24XX(isp)) { + ct7_entry_t *ct = arg; - if (IS_FC(isp)) { - ct2_entry_t *ct = arg; - atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid); + atp = isp_get_atpd(isp, tptr, ct->ct_rxid); if (atp == NULL) { - isp_prt(isp, ISP_LOGERR, - "cannot find adjunct for %x after I/O", - ct->ct_rxid); - return (0); + rls_lun_statep(isp, tptr); + isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid); + return; + } + + sentstatus = ct->ct_flags & CT7_SENDSTATUS; + ok = (ct->ct_nphdl == CT7_OK); + if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { + ccb->ccb_h.status |= CAM_SENT_SENSE; + } + notify_cam = ct->ct_header.rqs_seqno & 0x1; + if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) { + resid = ct->ct_resid; + atp->bytes_xfered += (atp->last_xframt - resid); + atp->last_xframt = 0; + } + if (ct->ct_nphdl == CT_HBA_RESET) { + ok = 0; + notify_cam = 1; + sentstatus = 1; + ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; + } else if (!ok) { + ccb->ccb_h.status |= CAM_REQ_CMP_ERR; + } + tval = atp->tag; + isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__, + ct->ct_rxid, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID"); + atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */ + } else if (IS_FC(isp)) { + ct2_entry_t *ct = arg; + + atp = isp_get_atpd(isp, tptr, ct->ct_rxid); + if (atp == NULL) { + rls_lun_statep(isp, tptr); + isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid); + return; } sentstatus = ct->ct_flags & CT2_SENDSTATUS; ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; @@ -1733,18 +2365,18 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) atp->bytes_xfered += (atp->last_xframt - resid); atp->last_xframt = 0; } - if (sentstatus || !ok) { - atp->tag = 0; + if (ct->ct_status == CT_HBA_RESET) { + ok = 0; + notify_cam = 1; + sentstatus = 1; + ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; + } else if (!ok) { + ccb->ccb_h.status |= CAM_REQ_CMP_ERR; } - isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, - "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", - ct->ct_rxid, ct->ct_status, ct->ct_flags, - (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, - resid, sentstatus? "FIN" : "MID"); - tval = ct->ct_rxid; - - /* XXX: should really come after isp_complete_ctio */ - atp->state = ATPD_STATE_PDON; + isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__, + ct->ct_rxid, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID"); + tval = atp->tag; + atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */ } else { ct_entry_t *ct = arg; sentstatus = ct->ct_flags & CT_SENDSTATUS; @@ -1759,22 +2391,25 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) * the auto-replenish feature for CTIOs. */ notify_cam = ct->ct_header.rqs_seqno & 0x1; - if (ct->ct_status & QLTM_SVALID) { + if (ct->ct_status == (CT_HBA_RESET & 0xff)) { + ok = 0; + notify_cam = 1; + sentstatus = 1; + ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; + } else if (!ok) { + ccb->ccb_h.status |= CAM_REQ_CMP_ERR; + } else if (ct->ct_status & QLTM_SVALID) { char *sp = (char *)ct; sp += CTIO_SENSE_OFFSET; - ccb->csio.sense_len = - min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); - MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); + ccb->csio.sense_len = min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN); + ISP_MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len); ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { resid = ct->ct_resid; } - isp_prt(isp, ISP_LOGTDEBUG0, - "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s", - ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, - ct->ct_status, ct->ct_flags, resid, - sentstatus? "FIN" : "MID"); + isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] tag %x S_ID 0x%x lun %d sts %x flg %x resid %d %s", __func__, + ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID"); tval = ct->ct_fwhandle; } ccb->csio.resid += resid; @@ -1791,86 +2426,1332 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) */ if (notify_cam == 0) { isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO[0x%x] done", tval); - return (0); + return; } + if (tptr) { + rls_lun_statep(isp, tptr); + } + isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", (sentstatus)? " FINAL " : "MIDTERM ", tval); - isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", - (sentstatus)? " FINAL " : "MIDTERM ", tval); - - if (!ok) { + if (!ok && !IS_24XX(isp)) { isp_target_putback_atio(ccb); } else { isp_complete_ctio(ccb); - } - return (0); } -static int -isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp) +static void +isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inot) { - return (0); /* XXXX */ + (void) isp_notify_ack(isp, inot); } -static int +static void isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp) { - + int needack = 1; switch (inp->in_status) { case IN_PORT_LOGOUT: - isp_prt(isp, ISP_LOGWARN, "port logout of iid %d", - inp->in_iid); + /* + * XXX: Need to delete this initiator's WWN from the database + * XXX: Need to send this LOGOUT upstream + */ + isp_prt(isp, ISP_LOGWARN, "port logout of S_ID 0x%x", inp->in_iid); break; case IN_PORT_CHANGED: - isp_prt(isp, ISP_LOGWARN, "port changed for iid %d", - inp->in_iid); + isp_prt(isp, ISP_LOGWARN, "port changed for S_ID 0x%x", inp->in_iid); break; case IN_GLOBAL_LOGO: + isp_del_all_wwn_entries(isp, 0); isp_prt(isp, ISP_LOGINFO, "all ports logged out"); break; case IN_ABORT_TASK: { - atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid); - struct ccb_immed_notify *inot = NULL; + tstate_t *tptr; + uint16_t lun; + uint32_t loopid; + uint64_t wwn; + atio_private_data_t *atp; + fcportdb_t *lp; + struct ccb_immediate_notify *inot = NULL; + + if (ISP_CAP_SCCFW(isp)) { + lun = inp->in_scclun; + } else { + lun = inp->in_lun; + } + if (ISP_CAP_2KLOGIN(isp)) { + loopid = ((in_fcentry_e_t *)inot)->in_iid; + } else { + loopid = inp->in_iid; + } + if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) { + wwn = lp->port_wwn; + } else { + wwn = INI_ANY; + } + tptr = get_lun_statep(isp, 0, lun); + if (tptr == NULL) { + tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD); + if (tptr == NULL) { + isp_prt(isp, ISP_LOGWARN, "ABORT TASK for lun %u- but no tstate", lun); + return; + } + } + atp = isp_get_atpd(isp, tptr, inp->in_seqid); if (atp) { - tstate_t *tptr = get_lun_statep(isp, 0, atp->lun); - if (tptr) { - inot = (struct ccb_immed_notify *) - SLIST_FIRST(&tptr->inots); - if (inot) { - tptr->inot_count--; - SLIST_REMOVE_HEAD(&tptr->inots, - sim_links.sle); - isp_prt(isp, ISP_LOGTDEBUG0, - "Take FREE INOT count now %d", - tptr->inot_count); - } + inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots); + isp_prt(isp, ISP_LOGTDEBUG0, "ABORT TASK RX_ID %x WWN 0x%016llx state %d", inp->in_seqid, (unsigned long long) wwn, atp->state); + if (inot) { + tptr->inot_count--; + SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count); + } else { + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "out of INOT structures\n"); } - isp_prt(isp, ISP_LOGWARN, - "abort task RX_ID %x IID %d state %d", - inp->in_seqid, inp->in_iid, atp->state); } else { - isp_prt(isp, ISP_LOGWARN, - "abort task RX_ID %x from iid %d, state unknown", - inp->in_seqid, inp->in_iid); + ISP_PATH_PRT(isp, ISP_LOGWARN, tptr->owner, "abort task RX_ID %x from wwn 0x%016llx, state unknown\n", inp->in_seqid, wwn); } if (inot) { - inot->initiator_id = inp->in_iid; - inot->sense_len = 0; - inot->message_args[0] = MSG_ABORT_TAG; - inot->message_args[1] = inp->in_seqid & 0xff; - inot->message_args[2] = (inp->in_seqid >> 8) & 0xff; - inot->ccb_h.status = CAM_MESSAGE_RECV; - xpt_done((union ccb *)inot); + isp_notify_t tmp, *nt = &tmp; + ISP_MEMZERO(nt, sizeof (isp_notify_t)); + nt->nt_hba = isp; + nt->nt_tgt = FCPARAM(isp, 0)->isp_wwpn; + nt->nt_wwn = wwn; + nt->nt_nphdl = loopid; + nt->nt_sid = PORT_ANY; + nt->nt_did = PORT_ANY; + nt->nt_lun = lun; + nt->nt_need_ack = 1; + nt->nt_channel = 0; + nt->nt_ncode = NT_ABORT_TASK; + nt->nt_lreserved = inot; + isp_handle_platform_target_tmf(isp, nt); + needack = 0; } + rls_lun_statep(isp, tptr); break; } default: break; } + if (needack) { + (void) isp_notify_ack(isp, inp); + } +} + +static void +isp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot) +{ + uint16_t nphdl; + uint32_t portid; + fcportdb_t *lp; + uint8_t *ptr = NULL; + uint64_t wwn; + + nphdl = inot->in_nphdl; + if (nphdl != NIL_HANDLE) { + portid = inot->in_portid_hi << 16 | inot->in_portid_lo; + } else { + portid = PORT_ANY; + } + + switch (inot->in_status) { + case IN24XX_ELS_RCVD: + { + char buf[16], *msg; + int chan = ISP_GET_VPIDX(isp, inot->in_vpidx); + + /* + * Note that we're just getting notification that an ELS was received + * (possibly with some associcated information sent upstream). This is + * *not* the same as being given the ELS frame to accept or reject. + */ + switch (inot->in_status_subcode) { + case LOGO: + msg = "LOGO"; + if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) { + ptr = (uint8_t *)inot; /* point to unswizzled entry! */ + wwn = (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF]) << 56) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+1]) << 48) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+2]) << 40) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+3]) << 32) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+4]) << 24) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+5]) << 16) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+6]) << 8) | + (((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+7])); + } else { + wwn = INI_ANY; + } + isp_del_wwn_entry(isp, chan, wwn, nphdl, portid); + break; + case PRLO: + msg = "PRLO"; + break; + case PLOGI: + msg = "PLOGI"; + if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) { + ptr = (uint8_t *)inot; /* point to unswizzled entry! */ + wwn = (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF]) << 56) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+1]) << 48) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+2]) << 40) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+3]) << 32) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+4]) << 24) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+5]) << 16) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+6]) << 8) | + (((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+7])); + } else { + wwn = INI_NONE; + } + isp_add_wwn_entry(isp, chan, wwn, nphdl, portid); + break; + case PRLI: + msg = "PRLI"; + break; + case PDISC: + msg = "PDISC"; + break; + case ADISC: + msg = "ADISC"; + break; + default: + ISP_SNPRINTF(buf, sizeof (buf), "ELS 0x%x", inot->in_status_subcode); + msg = buf; + break; + } + if (inot->in_flags & IN24XX_FLAG_PUREX_IOCB) { + isp_prt(isp, ISP_LOGERR, "%s Chan %d ELS N-port handle %x PortID 0x%06x marked as needing a PUREX response", msg, chan, nphdl, portid); + break; + } + isp_prt(isp, ISP_LOGTDEBUG0, "%s Chan %d ELS N-port handle %x PortID 0x%06x RX_ID 0x%x OX_ID 0x%x", msg, chan, nphdl, portid, + inot->in_rxid, inot->in_oxid); + (void) isp_notify_ack(isp, inot); + break; + } + + case IN24XX_PORT_LOGOUT: + ptr = "PORT LOGOUT"; + if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) { + isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid); + } + /* FALLTHROUGH */ + case IN24XX_PORT_CHANGED: + if (ptr == NULL) { + ptr = "PORT CHANGED"; + } + /* FALLTHROUGH */ + case IN24XX_LIP_RESET: + if (ptr == NULL) { + ptr = "LIP RESET"; + } + isp_prt(isp, ISP_LOGINFO, "Chan %d %s (sub-status 0x%x) for N-port handle 0x%x", ISP_GET_VPIDX(isp, inot->in_vpidx), ptr, inot->in_status_subcode, nphdl); + + /* + * All subcodes here are irrelevant. What is relevant + * is that we need to terminate all active commands from + * this initiator (known by N-port handle). + */ + /* XXX IMPLEMENT XXX */ + (void) isp_notify_ack(isp, inot); + break; + + case IN24XX_LINK_RESET: + case IN24XX_LINK_FAILED: + case IN24XX_SRR_RCVD: + default: + (void) isp_notify_ack(isp, inot); + break; + } +} + +static int +isp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp) +{ + + if (isp->isp_state != ISP_RUNSTATE) { + isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) acked- h/w not ready (dropping)", mp->nt_ncode, mp->nt_lreserved != NULL); + return (0); + } + + /* + * This case is for a Task Management Function, which shows up as an ATIO7 entry. + */ + if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ATIO) { + ct7_entry_t local, *cto = &local; + at7_entry_t *aep = (at7_entry_t *)mp->nt_lreserved; + fcportdb_t *lp; + uint32_t sid; + uint16_t nphdl; + + sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; + if (isp_find_pdb_by_sid(isp, mp->nt_channel, sid, &lp)) { + nphdl = lp->handle; + } else { + nphdl = NIL_HANDLE; + } + ISP_MEMZERO(&local, sizeof (local)); + cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + cto->ct_header.rqs_entry_count = 1; + cto->ct_nphdl = nphdl; + cto->ct_rxid = aep->at_rxid; + cto->ct_vpidx = mp->nt_channel; + cto->ct_iid_lo = sid; + cto->ct_iid_hi = sid >> 16; + cto->ct_oxid = aep->at_hdr.ox_id; + cto->ct_flags = CT7_SENDSTATUS|CT7_NOACK|CT7_NO_DATA|CT7_FLAG_MODE1; + cto->ct_flags |= (aep->at_ta_len >> 12) << CT7_TASK_ATTR_SHIFT; + return (isp_target_put_entry(isp, &local)); + } + + /* + * This case is for a responding to an ABTS frame + */ + if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) { + + /* + * Overload nt_need_ack here to mark whether we've terminated the associated command. + */ + if (mp->nt_need_ack) { + uint8_t storage[QENTRY_LEN]; + ct7_entry_t *cto = (ct7_entry_t *) storage; + abts_t *abts = (abts_t *)mp->nt_lreserved; + + ISP_MEMZERO(cto, sizeof (ct7_entry_t)); + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task); + cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + cto->ct_header.rqs_entry_count = 1; + cto->ct_nphdl = mp->nt_nphdl; + cto->ct_rxid = abts->abts_rxid_task; + cto->ct_iid_lo = mp->nt_sid; + cto->ct_iid_hi = mp->nt_sid >> 16; + cto->ct_oxid = abts->abts_ox_id; + cto->ct_vpidx = mp->nt_channel; + cto->ct_flags = CT7_NOACK|CT7_TERMINATE; + if (isp_target_put_entry(isp, cto)) { + return (ENOMEM); + } + mp->nt_need_ack = 0; + } + if (isp_acknak_abts(isp, mp->nt_lreserved, 0) == ENOMEM) { + return (ENOMEM); + } else { + return (0); + } + } + + /* + * Handle logout cases here + */ + if (mp->nt_ncode == NT_GLOBAL_LOGOUT) { + isp_del_all_wwn_entries(isp, mp->nt_channel); + } + + if (mp->nt_ncode == NT_LOGOUT) { + if (!IS_2100(isp) && IS_FC(isp)) { + isp_del_wwn_entries(isp, mp); + } + } + + /* + * General purpose acknowledgement + */ + if (mp->nt_need_ack) { + isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) being acked", mp->nt_ncode, mp->nt_lreserved != NULL); + return (isp_notify_ack(isp, mp->nt_lreserved)); + } return (0); } + +/* + * Handle task managment functions. + * + * We show up here with a notify structure filled out. + * + * The nt_lreserved tag points to the original queue entry + */ +static void +isp_handle_platform_target_tmf(ispsoftc_t *isp, isp_notify_t *notify) +{ + tstate_t *tptr; + fcportdb_t *lp; + struct ccb_immediate_notify *inot; + inot_private_data_t *ntp = NULL; + lun_id_t lun; + + isp_prt(isp, ISP_LOGTDEBUG0, "%s: code 0x%x sid 0x%x tagval 0x%016llx chan %d lun 0x%x", __func__, notify->nt_ncode, + notify->nt_sid, (unsigned long long) notify->nt_tagval, notify->nt_channel, notify->nt_lun); + /* + * NB: This assignment is necessary because of tricky type conversion. + * XXX: This is tricky and I need to check this. If the lun isn't known + * XXX: for the task management function, it does not of necessity follow + * XXX: that it should go up stream to the wildcard listener. + */ + if (notify->nt_lun == LUN_ANY) { + lun = CAM_LUN_WILDCARD; + } else { + lun = notify->nt_lun; + } + tptr = get_lun_statep(isp, notify->nt_channel, lun); + if (tptr == NULL) { + tptr = get_lun_statep(isp, notify->nt_channel, CAM_LUN_WILDCARD); + if (tptr == NULL) { + isp_prt(isp, ISP_LOGWARN, "%s: no state pointer found for chan %d lun 0x%x", __func__, notify->nt_channel, lun); + goto bad; + } + } + inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots); + if (inot == NULL) { + isp_prt(isp, ISP_LOGWARN, "%s: out of immediate notify structures for chan %d lun 0x%x", __func__, notify->nt_channel, lun); + goto bad; + } + + if (isp_find_pdb_by_sid(isp, notify->nt_channel, notify->nt_sid, &lp) == 0) { + inot->initiator_id = CAM_TARGET_WILDCARD; + } else { + inot->initiator_id = lp->handle; + } + inot->seq_id = notify->nt_tagval; + inot->tag_id = notify->nt_tagval >> 32; + + switch (notify->nt_ncode) { + case NT_ABORT_TASK: + isp_target_mark_aborted_early(isp, tptr, inot->tag_id); + inot->arg = MSG_ABORT_TASK; + break; + case NT_ABORT_TASK_SET: + isp_target_mark_aborted_early(isp, tptr, TAG_ANY); + inot->arg = MSG_ABORT_TASK_SET; + break; + case NT_CLEAR_ACA: + inot->arg = MSG_CLEAR_ACA; + break; + case NT_CLEAR_TASK_SET: + inot->arg = MSG_CLEAR_TASK_SET; + break; + case NT_LUN_RESET: + inot->arg = MSG_LOGICAL_UNIT_RESET; + break; + case NT_TARGET_RESET: + inot->arg = MSG_TARGET_RESET; + break; + default: + isp_prt(isp, ISP_LOGWARN, "%s: unknown TMF code 0x%x for chan %d lun 0x%x", __func__, notify->nt_ncode, notify->nt_channel, lun); + goto bad; + } + + ntp = isp_get_ntpd(isp, tptr); + if (ntp == NULL) { + isp_prt(isp, ISP_LOGWARN, "%s: out of inotify private structures", __func__); + goto bad; + } + ISP_MEMCPY(&ntp->rd.nt, notify, sizeof (isp_notify_t)); + if (notify->nt_lreserved) { + ISP_MEMCPY(&ntp->rd.data, notify->nt_lreserved, QENTRY_LEN); + ntp->rd.nt.nt_lreserved = &ntp->rd.data; + } + ntp->rd.seq_id = notify->nt_tagval; + ntp->rd.tag_id = notify->nt_tagval >> 32; + + tptr->inot_count--; + SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle); + rls_lun_statep(isp, tptr); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count); + inot->ccb_h.status = CAM_MESSAGE_RECV; + xpt_done((union ccb *)inot); + return; +bad: + if (tptr) { + rls_lun_statep(isp, tptr); + } + if (notify->nt_need_ack && notify->nt_lreserved) { + if (((isphdr_t *)notify->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) { + (void) isp_acknak_abts(isp, notify->nt_lreserved, ENOMEM); + } else { + (void) isp_notify_ack(isp, notify->nt_lreserved); + } + } +} + +/* + * Find the associated private data and makr it as dead so + * we don't try to work on it any further. + */ +static void +isp_target_mark_aborted(ispsoftc_t *isp, union ccb *ccb) +{ + tstate_t *tptr; + atio_private_data_t *atp; + + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb)); + if (tptr == NULL) { + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD); + if (tptr == NULL) { + ccb->ccb_h.status = CAM_REQ_INVALID; + return; + } + } + + atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id); + if (atp == NULL) { + ccb->ccb_h.status = CAM_REQ_INVALID; + return; + } + atp->dead = 1; + ccb->ccb_h.status = CAM_REQ_CMP; +} + +static void +isp_target_mark_aborted_early(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id) +{ + atio_private_data_t *atp; + inot_private_data_t *restart_queue = tptr->restart_queue; + + /* + * First, clean any commands pending restart + */ + tptr->restart_queue = NULL; + while (restart_queue) { + uint32_t this_tag_id; + inot_private_data_t *ntp = restart_queue; + + restart_queue = ntp->rd.nt.nt_hba; + + if (IS_24XX(isp)) { + this_tag_id = ((at7_entry_t *)ntp->rd.data)->at_rxid; + } else { + this_tag_id = ((at2_entry_t *)ntp->rd.data)->at_rxid; + } + if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) { + isp_put_ntpd(isp, tptr, ntp); + } else { + ntp->rd.nt.nt_hba = tptr->restart_queue; + tptr->restart_queue = ntp; + } + } + + /* + * Now mark other ones dead as well. + */ + for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) { + if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) { + atp->dead = 1; + } + } +} + + +#ifdef ISP_INTERNAL_TARGET +// #define ISP_FORCE_TIMEOUT 1 +#define ISP_TEST_WWNS 1 +#define ISP_TEST_SEPARATE_STATUS 1 + +#define ccb_data_offset ppriv_field0 +#define ccb_atio ppriv_ptr1 +#define ccb_inot ppriv_ptr1 + +#define MAX_ISP_TARG_TRANSFER (2 << 20) +#define NISP_TARG_CMDS 1024 +#define NISP_TARG_NOTIFIES 1024 +#define DISK_SHIFT 9 +#define JUNK_SIZE 256 + +#ifndef VERIFY_10 +#define VERIFY_10 0x2f +#endif + +TAILQ_HEAD(ccb_queue, ccb_hdr); +extern u_int vm_kmem_size; +static int ca; +static uint32_t disk_size; +static uint8_t *disk_data = NULL; +static uint8_t *junk_data; +static MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data"); +struct isptarg_softc { + /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ + struct ccb_queue work_queue; + struct ccb_queue rework_queue; + struct ccb_queue running_queue; + struct ccb_queue inot_queue; + struct cam_periph *periph; + struct cam_path *path; + ispsoftc_t *isp; +}; +static periph_ctor_t isptargctor; +static periph_dtor_t isptargdtor; +static periph_start_t isptargstart; +static periph_init_t isptarginit; +static void isptarg_done(struct cam_periph *, union ccb *); +static void isptargasync(void *, u_int32_t, struct cam_path *, void *); + + +static int isptarg_rwparm(uint8_t *, uint8_t *, uint64_t, uint32_t, uint8_t **, uint32_t *, int *); + +static struct periph_driver isptargdriver = +{ + isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), /* generation */ 0 +}; + +static void +isptarginit(void) +{ +} + +static void +isptargnotify(ispsoftc_t *isp, union ccb *iccb, struct ccb_immediate_notify *inot) +{ + struct ccb_notify_acknowledge *ack = &iccb->cna2; + + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: [0x%x] immediate notify for 0x%x from 0x%x status 0x%x arg 0x%x\n", __func__, + inot->tag_id, inot->initiator_id, inot->seq_id, inot->ccb_h.status, inot->arg); + ack->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE; + ack->ccb_h.flags = 0; + ack->ccb_h.retry_count = 0; + ack->ccb_h.cbfcnp = isptarg_done; + ack->ccb_h.timeout = 0; + ack->ccb_h.ccb_inot = inot; + ack->tag_id = inot->tag_id; + ack->seq_id = inot->seq_id; + ack->initiator_id = inot->initiator_id; + xpt_action(iccb); +} + +static void +isptargstart(struct cam_periph *periph, union ccb *iccb) +{ + const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = { 0x7f }; + const uint8_t iqd[SHORT_INQUIRY_LENGTH] = { + 0, 0x0, 0x2, 0x2, 32, 0, 0, 0x32, + 'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ', + 'S', 'C', 'S', 'I', ' ', 'M', 'E', 'M', + 'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K', + '0', '0', '0', '1' + }; + int i, more = 0, last; + struct isptarg_softc *softc = periph->softc; + struct ccb_scsiio *csio; + lun_id_t return_lun; + struct ccb_accept_tio *atio; + uint8_t *cdb, *ptr, status; + uint8_t *data_ptr; + uint32_t data_len, flags; + struct ccb_hdr *ccbh; + + mtx_assert(periph->sim->mtx, MA_OWNED); + ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: function code 0x%x INOTQ=%c WORKQ=%c REWORKQ=%c\n", __func__, iccb->ccb_h.func_code, + TAILQ_FIRST(&softc->inot_queue)? 'y' : 'n', TAILQ_FIRST(&softc->work_queue)? 'y' : 'n', TAILQ_FIRST(&softc->rework_queue)? 'y' : 'n'); + /* + * Check for immediate notifies first + */ + ccbh = TAILQ_FIRST(&softc->inot_queue); + if (ccbh) { + TAILQ_REMOVE(&softc->inot_queue, ccbh, periph_links.tqe); + if (TAILQ_FIRST(&softc->inot_queue) || TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue)) { + xpt_schedule(periph, 1); + } + isptargnotify(softc->isp, iccb, (struct ccb_immediate_notify *)ccbh); + return; + } + + /* + * Check the rework (continuation) work queue first. + */ + ccbh = TAILQ_FIRST(&softc->rework_queue); + if (ccbh) { + atio = (struct ccb_accept_tio *)ccbh; + TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe); + more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue); + } else { + ccbh = TAILQ_FIRST(&softc->work_queue); + if (ccbh == NULL) { + ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: woken up but no work?\n", __func__); + xpt_release_ccb(iccb); + return; + } + atio = (struct ccb_accept_tio *)ccbh; + TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); + more = TAILQ_FIRST(&softc->work_queue) != NULL; + atio->ccb_h.ccb_data_offset = 0; + } + + if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) { + panic("BAD ATIO"); + } + + data_ptr = NULL; + data_len = 0; + csio = &iccb->csio; + status = SCSI_STATUS_OK; + flags = CAM_SEND_STATUS; + memset(&atio->sense_data, 0, sizeof (atio->sense_data)); + cdb = atio->cdb_io.cdb_bytes; + ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, ccbh->path, "%s: [0x%x] processing ATIO from 0x%x CDB=0x%x data_offset=%u\n", __func__, atio->tag_id, atio->init_id, + cdb[0], atio->ccb_h.ccb_data_offset); + + return_lun = XS_LUN(atio); + if (return_lun != 0) { + xpt_print(atio->ccb_h.path, "[0x%x] Non-Zero Lun %d: cdb0=0x%x\n", atio->tag_id, return_lun, cdb[0]); + if (cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) { + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_ILLEGAL_REQUEST; + atio->sense_data.add_sense_code = 0x25; + atio->sense_data.add_sense_code_qual = 0x0; + atio->sense_len = sizeof (atio->sense_data); + } + return_lun = CAM_LUN_WILDCARD; + } + + switch (cdb[0]) { + case REQUEST_SENSE: + flags |= CAM_DIR_IN; + data_len = sizeof (atio->sense_data); + junk_data[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_NO_SENSE; + memset(junk_data+1, 0, data_len-1); + if (data_len > cdb[4]) { + data_len = cdb[4]; + } + if (data_len) { + data_ptr = junk_data; + } + break; + case READ_6: + case READ_10: + case READ_12: + case READ_16: + if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) { + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x5; + atio->sense_data.add_sense_code_qual = 0x24; + atio->sense_len = sizeof (atio->sense_data); + } else { +#ifdef ISP_FORCE_TIMEOUT + { + static int foo; + if (foo++ == 500) { + if (more) { + xpt_schedule(periph, 1); + } + foo = 0; + return; + } + } +#endif +#ifdef ISP_TEST_SEPARATE_STATUS + if (last && data_len) { + last = 0; + } +#endif + if (last == 0) { + flags &= ~CAM_SEND_STATUS; + } + if (data_len) { + atio->ccb_h.ccb_data_offset += data_len; + flags |= CAM_DIR_IN; + } else { + flags |= CAM_DIR_NONE; + } + } + break; + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) { + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x5; + atio->sense_data.add_sense_code_qual = 0x24; + atio->sense_len = sizeof (atio->sense_data); + } else { +#ifdef ISP_FORCE_TIMEOUT + { + static int foo; + if (foo++ == 500) { + if (more) { + xpt_schedule(periph, 1); + } + foo = 0; + return; + } + } +#endif +#ifdef ISP_TEST_SEPARATE_STATUS + if (last && data_len) { + last = 0; + } +#endif + if (last == 0) { + flags &= ~CAM_SEND_STATUS; + } + if (data_len) { + atio->ccb_h.ccb_data_offset += data_len; + flags |= CAM_DIR_OUT; + } else { + flags |= CAM_DIR_NONE; + } + } + break; + case INQUIRY: + flags |= CAM_DIR_IN; + if (cdb[1] || cdb[2] || cdb[3]) { + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x5; + atio->sense_data.add_sense_code_qual = 0x20; + atio->sense_len = sizeof (atio->sense_data); + break; + } + data_len = sizeof (iqd); + if (data_len > cdb[4]) { + data_len = cdb[4]; + } + if (data_len) { + if (XS_LUN(iccb) != 0) { + memcpy(junk_data, niliqd, sizeof (iqd)); + } else { + memcpy(junk_data, iqd, sizeof (iqd)); + } + data_ptr = junk_data; + } + break; + case TEST_UNIT_READY: + flags |= CAM_DIR_NONE; + if (ca) { + ca = 0; + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x28; + atio->sense_data.add_sense_code_qual = 0x0; + atio->sense_len = sizeof (atio->sense_data); + } + break; + case SYNCHRONIZE_CACHE: + case START_STOP: + case RESERVE: + case RELEASE: + case VERIFY_10: + flags |= CAM_DIR_NONE; + break; + + case READ_CAPACITY: + flags |= CAM_DIR_IN; + if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) { + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x5; + atio->sense_data.add_sense_code_qual = 0x24; + atio->sense_len = sizeof (atio->sense_data); + break; + } + if (cdb[8] & 0x1) { /* PMI */ + junk_data[0] = 0xff; + junk_data[1] = 0xff; + junk_data[2] = 0xff; + junk_data[3] = 0xff; + } else { + uint64_t last_blk = (disk_size >> DISK_SHIFT) - 1; + if (last_blk < 0xffffffffULL) { + junk_data[0] = (last_blk >> 24) & 0xff; + junk_data[1] = (last_blk >> 16) & 0xff; + junk_data[2] = (last_blk >> 8) & 0xff; + junk_data[3] = (last_blk) & 0xff; + } else { + junk_data[0] = 0xff; + junk_data[1] = 0xff; + junk_data[2] = 0xff; + junk_data[3] = 0xff; + } + } + junk_data[4] = ((1 << DISK_SHIFT) >> 24) & 0xff; + junk_data[5] = ((1 << DISK_SHIFT) >> 16) & 0xff; + junk_data[6] = ((1 << DISK_SHIFT) >> 8) & 0xff; + junk_data[7] = ((1 << DISK_SHIFT)) & 0xff; + data_ptr = junk_data; + data_len = 8; + break; + case REPORT_LUNS: + flags |= CAM_DIR_IN; + memset(junk_data, 0, JUNK_SIZE); + junk_data[0] = (1 << 3) >> 24; + junk_data[1] = (1 << 3) >> 16; + junk_data[2] = (1 << 3) >> 8; + junk_data[3] = (1 << 3); + ptr = NULL; + for (i = 0; i < 1; i++) { + ptr = &junk_data[8 + (1 << 3)]; + if (i >= 256) { + ptr[0] = 0x40 | ((i >> 8) & 0x3f); + } + ptr[1] = i; + } + data_ptr = junk_data; + data_len = (ptr + 8) - junk_data; + break; + + default: + flags |= CAM_DIR_NONE; + status = SCSI_STATUS_CHECK_COND; + atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION; + atio->sense_data.add_sense_code = 0x5; + atio->sense_data.add_sense_code_qual = 0x20; + atio->sense_len = sizeof (atio->sense_data); + break; + } + + /* + * If we are done with the transaction, tell the + * controller to send status and perform a CMD_CMPLT. + * If we have associated sense data, see if we can + * send that too. + */ + if (status == SCSI_STATUS_CHECK_COND) { + flags |= CAM_SEND_SENSE; + csio->sense_len = atio->sense_len; + csio->sense_data = atio->sense_data; + flags &= ~CAM_DIR_MASK; + data_len = 0; + data_ptr = NULL; + } + cam_fill_ctio(csio, 0, isptarg_done, flags, MSG_SIMPLE_Q_TAG, atio->tag_id, atio->init_id, status, data_ptr, data_len, 0); + iccb->ccb_h.target_id = atio->ccb_h.target_id; + iccb->ccb_h.target_lun = return_lun; + iccb->ccb_h.ccb_atio = atio; + xpt_action(iccb); + + if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) { + cam_release_devq(periph->path, 0, 0, 0, 0); + atio->ccb_h.status &= ~CAM_DEV_QFRZN; + } + if (more) { + xpt_schedule(periph, 1); + } +} + +static cam_status +isptargctor(struct cam_periph *periph, void *arg) +{ + struct isptarg_softc *softc; + + softc = (struct isptarg_softc *)arg; + periph->softc = softc; + softc->periph = periph; + softc->path = periph->path; + ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__); + return (CAM_REQ_CMP); +} + +static void +isptargdtor(struct cam_periph *periph) +{ + struct isptarg_softc *softc; + softc = (struct isptarg_softc *)periph->softc; + ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__); + softc->periph = NULL; + softc->path = NULL; + periph->softc = NULL; +} + +static void +isptarg_done(struct cam_periph *periph, union ccb *ccb) +{ + struct isptarg_softc *softc; + ispsoftc_t *isp; + struct ccb_accept_tio *atio; + struct ccb_immediate_notify *inot; + cam_status status; + + softc = (struct isptarg_softc *)periph->softc; + isp = softc->isp; + status = ccb->ccb_h.status & CAM_STATUS_MASK; + + switch (ccb->ccb_h.func_code) { + case XPT_ACCEPT_TARGET_IO: + atio = (struct ccb_accept_tio *) ccb; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__); + TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe); + xpt_schedule(periph, 1); + break; + case XPT_IMMEDIATE_NOTIFY: + inot = (struct ccb_immediate_notify *) ccb; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] INOT for 0x%x seen in %s\n", inot->tag_id, inot->seq_id, __func__); + TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe); + xpt_schedule(periph, 1); + break; + case XPT_CONT_TARGET_IO: + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); + ccb->ccb_h.status &= ~CAM_DEV_QFRZN; + } + atio = ccb->ccb_h.ccb_atio; + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL); + xpt_action((union ccb *)atio); + } else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO seen in %s\n", atio->tag_id, __func__); + TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); + xpt_schedule(periph, 1); + } else { + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO seen in %s\n", atio->tag_id, __func__); + xpt_action((union ccb *)atio); + } + xpt_release_ccb(ccb); + break; + case XPT_NOTIFY_ACKNOWLEDGE: + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); + ccb->ccb_h.status &= ~CAM_DEV_QFRZN; + } + inot = ccb->ccb_h.ccb_inot; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "[0x%x] recycle notify for tag 0x%x\n", inot->tag_id, inot->seq_id); + xpt_release_ccb(ccb); + xpt_action((union ccb *)inot); + break; + default: + xpt_print(ccb->ccb_h.path, "unexpected code 0x%x\n", ccb->ccb_h.func_code); + break; + } +} + +static void +isptargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) +{ + struct ac_contract *acp = arg; + struct ac_device_changed *fc = (struct ac_device_changed *) acp->contract_data; + + if (code != AC_CONTRACT) { + return; + } + xpt_print(path, "0x%016llx Port ID 0x%06x %s\n", (unsigned long long) fc->wwpn, fc->port, fc->arrived? "arrived" : "departed"); +} + +static void +isp_target_thread(ispsoftc_t *isp, int chan) +{ + union ccb *ccb = NULL; + int i; + void *wchan; + cam_status status; + struct isptarg_softc *softc = NULL; + struct cam_periph *periph = NULL, *wperiph = NULL; + struct cam_path *path, *wpath; + struct cam_sim *sim; + + if (disk_data == NULL) { + disk_size = roundup2(vm_kmem_size >> 1, (1ULL << 20)); + if (disk_size < (50 << 20)) { + disk_size = 50 << 20; + } + disk_data = malloc(disk_size, M_ISPTARG, M_WAITOK | M_ZERO); + if (disk_data == NULL) { + isp_prt(isp, ISP_LOGERR, "%s: could not allocate disk data", __func__); + goto out; + } + isp_prt(isp, ISP_LOGINFO, "allocated a %ju MiB disk", (uintmax_t) (disk_size >> 20)); + } + junk_data = malloc(JUNK_SIZE, M_ISPTARG, M_WAITOK | M_ZERO); + if (junk_data == NULL) { + isp_prt(isp, ISP_LOGERR, "%s: could not allocate junk", __func__); + goto out; + } + + + softc = malloc(sizeof (*softc), M_ISPTARG, M_WAITOK | M_ZERO); + if (softc == NULL) { + isp_prt(isp, ISP_LOGERR, "%s: could not allocate softc", __func__); + goto out; + } + TAILQ_INIT(&softc->work_queue); + TAILQ_INIT(&softc->rework_queue); + TAILQ_INIT(&softc->running_queue); + TAILQ_INIT(&softc->inot_queue); + softc->isp = isp; + + periphdriver_register(&isptargdriver); + ISP_GET_PC(isp, chan, sim, sim); + ISP_GET_PC(isp, chan, path, path); + status = xpt_create_path_unlocked(&wpath, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); + if (status != CAM_REQ_CMP) { + isp_prt(isp, ISP_LOGERR, "%s: could not allocate wildcard path", __func__); + return; + } + status = xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), 0, 0); + if (status != CAM_REQ_CMP) { + xpt_free_path(wpath); + isp_prt(isp, ISP_LOGERR, "%s: could not allocate path", __func__); + return; + } + + ccb = xpt_alloc_ccb(); + + ISP_LOCK(isp); + status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, wpath, NULL, 0, softc); + if (status != CAM_REQ_CMP) { + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc for wildcard failed", __func__); + goto out; + } + wperiph = cam_periph_find(wpath, "isptarg"); + if (wperiph == NULL) { + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGERR, "%s: wildcard periph already allocated but doesn't exist", __func__); + goto out; + } + + status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, path, NULL, 0, softc); + if (status != CAM_REQ_CMP) { + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc failed", __func__); + goto out; + } + + periph = cam_periph_find(path, "isptarg"); + if (periph == NULL) { + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGERR, "%s: periph already allocated but doesn't exist", __func__); + goto out; + } + + status = xpt_register_async(AC_CONTRACT, isptargasync, isp, wpath); + if (status != CAM_REQ_CMP) { + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGERR, "%s: xpt_register_async failed", __func__); + goto out; + } + + ISP_UNLOCK(isp); + + ccb = xpt_alloc_ccb(); + + /* + * Make sure role is none. + */ + xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); + ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; + ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE; +#ifdef ISP_TEST_WWNS + ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE | KNOB_VALID_ADDRESS; + ccb->knob.xport_specific.fc.wwnn = 0x508004d000000000ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16); + ccb->knob.xport_specific.fc.wwpn = 0x508004d000000001ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16); +#else + ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE; +#endif + + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + + /* + * Now enable luns + */ + xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); + ccb->ccb_h.func_code = XPT_EN_LUN; + ccb->cel.enable = 1; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + if (ccb->ccb_h.status != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + xpt_print(periph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status); + goto out; + } + + xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 10); + ccb->ccb_h.func_code = XPT_EN_LUN; + ccb->cel.enable = 1; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + if (ccb->ccb_h.status != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + xpt_print(wperiph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status); + goto out; + } + xpt_free_ccb(ccb); + + /* + * Add resources + */ + ISP_GET_PC_ADDR(isp, chan, target_proc, wchan); + for (i = 0; i < 4; i++) { + ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); + xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1); + ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; + ccb->ccb_h.cbfcnp = isptarg_done; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + } + for (i = 0; i < NISP_TARG_CMDS; i++) { + ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); + xpt_setup_ccb(&ccb->ccb_h, periph->path, 1); + ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; + ccb->ccb_h.cbfcnp = isptarg_done; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + } + for (i = 0; i < 4; i++) { + ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); + xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1); + ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; + ccb->ccb_h.cbfcnp = isptarg_done; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + } + for (i = 0; i < NISP_TARG_NOTIFIES; i++) { + ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO); + xpt_setup_ccb(&ccb->ccb_h, periph->path, 1); + ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; + ccb->ccb_h.cbfcnp = isptarg_done; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + } + + /* + * Now turn it all back on + */ + xpt_setup_ccb(&ccb->ccb_h, periph->path, 10); + ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; + ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE; + ccb->knob.xport_specific.fc.role = KNOB_ROLE_TARGET; + ISP_LOCK(isp); + xpt_action(ccb); + ISP_UNLOCK(isp); + + /* + * Okay, while things are still active, sleep... + */ + ISP_LOCK(isp); + for (;;) { + ISP_GET_PC(isp, chan, proc_active, i); + if (i == 0) { + break; + } + msleep(wchan, &isp->isp_lock, PUSER, "tsnooze", 0); + } + ISP_UNLOCK(isp); + +out: + if (wperiph) { + cam_periph_invalidate(wperiph); + } + if (periph) { + cam_periph_invalidate(periph); + } + if (junk_data) { + free(junk_data, M_ISPTARG); + } + if (disk_data) { + free(disk_data, M_ISPTARG); + } + if (softc) { + free(softc, M_ISPTARG); + } + xpt_free_path(path); + xpt_free_path(wpath); +} + +static void +isp_target_thread_pi(void *arg) +{ + struct isp_spi *pi = arg; + isp_target_thread(cam_sim_softc(pi->sim), cam_sim_bus(pi->sim)); +} + +static void +isp_target_thread_fc(void *arg) +{ + struct isp_fc *fc = arg; + isp_target_thread(cam_sim_softc(fc->sim), cam_sim_bus(fc->sim)); +} + +static int +isptarg_rwparm(uint8_t *cdb, uint8_t *dp, uint64_t dl, uint32_t offset, uint8_t **kp, uint32_t *tl, int *lp) +{ + uint32_t cnt, curcnt; + uint64_t lba; + + switch (cdb[0]) { + case WRITE_16: + case READ_16: + cnt = (((uint32_t)cdb[10]) << 24) | + (((uint32_t)cdb[11]) << 16) | + (((uint32_t)cdb[12]) << 8) | + ((uint32_t)cdb[13]); + + lba = (((uint64_t)cdb[2]) << 56) | + (((uint64_t)cdb[3]) << 48) | + (((uint64_t)cdb[4]) << 40) | + (((uint64_t)cdb[5]) << 32) | + (((uint64_t)cdb[6]) << 24) | + (((uint64_t)cdb[7]) << 16) | + (((uint64_t)cdb[8]) << 8) | + ((uint64_t)cdb[9]); + break; + case WRITE_12: + case READ_12: + cnt = (((uint32_t)cdb[6]) << 16) | + (((uint32_t)cdb[7]) << 8) | + ((u_int32_t)cdb[8]); + + lba = (((uint32_t)cdb[2]) << 24) | + (((uint32_t)cdb[3]) << 16) | + (((uint32_t)cdb[4]) << 8) | + ((uint32_t)cdb[5]); + break; + case WRITE_10: + case READ_10: + cnt = (((uint32_t)cdb[7]) << 8) | + ((u_int32_t)cdb[8]); + + lba = (((uint32_t)cdb[2]) << 24) | + (((uint32_t)cdb[3]) << 16) | + (((uint32_t)cdb[4]) << 8) | + ((uint32_t)cdb[5]); + break; + case WRITE_6: + case READ_6: + cnt = cdb[4]; + if (cnt == 0) { + cnt = 256; + } + lba = (((uint32_t)cdb[1] & 0x1f) << 16) | + (((uint32_t)cdb[2]) << 8) | + ((uint32_t)cdb[3]); + break; + default: + return (-1); + } + + cnt <<= DISK_SHIFT; + lba <<= DISK_SHIFT; + + if (offset == cnt) { + *lp = 1; + return (0); + } + + if (lba + cnt > dl) { + return (-1); + } + + + curcnt = MAX_ISP_TARG_TRANSFER; + if (offset + curcnt >= cnt) { + curcnt = cnt - offset; + *lp = 1; + } else { + *lp = 0; + } + *tl = curcnt; + *kp = &dp[lba + offset]; + return (0); +} + +#endif #endif static void @@ -1885,12 +3766,12 @@ isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) case AC_LOST_DEVICE: if (IS_SCSI(isp)) { uint16_t oflags, nflags; - sdparam *sdp = isp->isp_param; + int bus = cam_sim_bus(sim); + sdparam *sdp = SDPARAM(isp, bus); int tgt; tgt = xpt_path_target_id(path); if (tgt >= 0) { - sdp += cam_sim_bus(sim); nflags = sdp->isp_devparam[tgt].nvrm_flags; #ifndef ISP_TARGET_MODE nflags &= DPARM_SAFE_DFLT; @@ -1903,9 +3784,8 @@ isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) oflags = sdp->isp_devparam[tgt].goal_flags; sdp->isp_devparam[tgt].goal_flags = nflags; sdp->isp_devparam[tgt].dev_update = 1; - isp->isp_update |= (1 << cam_sim_bus(sim)); - (void) isp_control(isp, - ISPCTL_UPDATE_PARAMS, NULL); + sdp->update = 1; + (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus); sdp->isp_devparam[tgt].goal_flags = oflags; } } @@ -1929,109 +3809,55 @@ isp_poll(struct cam_sim *sim) } -static int isp_watchdog_work(ispsoftc_t *, XS_T *); - -static int -isp_watchdog_work(ispsoftc_t *isp, XS_T *xs) -{ - uint32_t handle; - - /* - * We've decided this command is dead. Make sure we're not trying - * to kill a command that's already dead by getting it's handle and - * and seeing whether it's still alive. - */ - handle = isp_find_handle(isp, xs); - if (handle) { - uint32_t isr; - uint16_t sema, mbox; - - if (XS_CMD_DONE_P(xs)) { - isp_prt(isp, ISP_LOGDEBUG1, - "watchdog found done cmd (handle 0x%x)", handle); - return (1);; - } - - if (XS_CMD_WDOG_P(xs)) { - isp_prt(isp, ISP_LOGDEBUG2, - "recursive watchdog (handle 0x%x)", handle); - return (1); - } - - XS_CMD_S_WDOG(xs); - if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { - isp_intr(isp, isr, sema, mbox); - } - if (XS_CMD_DONE_P(xs)) { - isp_prt(isp, ISP_LOGDEBUG2, - "watchdog cleanup for handle 0x%x", handle); - isp_free_pcmd(isp, (union ccb *)xs); - xpt_done((union ccb *) xs); - } else if (XS_CMD_GRACE_P(xs)) { - /* - * Make sure the command is *really* dead before we - * release the handle (and DMA resources) for reuse. - */ - (void) isp_control(isp, ISPCTL_ABORT_CMD, xs); - - /* - * After this point, the comamnd is really dead. - */ - if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, handle); - } - isp_destroy_handle(isp, handle); - xpt_print(xs->ccb_h.path, - "watchdog timeout for handle 0x%x\n", handle); - XS_SETERR(xs, CAM_CMD_TIMEOUT); - XS_CMD_C_WDOG(xs); - isp_done(xs); - } else { - XS_CMD_C_WDOG(xs); - callout_reset(&PISP_PCMD((union ccb *)xs)->wdog, hz, - isp_watchdog, xs); - XS_CMD_S_GRACE(xs); - isp->isp_sendmarker |= 1 << XS_CHANNEL(xs); - } - return (1); - } - return (0); -} - static void isp_watchdog(void *arg) { + struct ccb_scsiio *xs = arg; ispsoftc_t *isp; - XS_T *xs = arg; - int r; + uint32_t handle; - for (r = 0, isp = isplist; r && isp; isp = isp->isp_osinfo.next) { - ISP_LOCK(isp); - r = isp_watchdog_work(isp, xs); - ISP_UNLOCK(isp); - } - if (isp == NULL) { - printf("isp_watchdog: nobody had %p active\n", arg); + isp = XS_ISP(xs); + + handle = isp_find_handle(isp, xs); + if (handle) { + /* + * Make sure the command is *really* dead before we + * release the handle (and DMA resources) for reuse. + */ + (void) isp_control(isp, ISPCTL_ABORT_CMD, xs); + + /* + * After this point, the comamnd is really dead. + */ + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, handle); + } + isp_destroy_handle(isp, handle); + xpt_print(xs->ccb_h.path, "watchdog timeout for handle 0x%x\n", handle); + XS_SETERR(xs, CAM_CMD_TIMEOUT); + isp_done(xs); } } - -#if __FreeBSD_version >= 600000 static void -isp_make_here(ispsoftc_t *isp, int tgt) +isp_make_here(ispsoftc_t *isp, int chan, int tgt) { union ccb *ccb; + struct isp_fc *fc = ISP_FC_PC(isp, chan); + + if (isp_autoconfig == 0) { + return; + } + /* - * Allocate a CCB, create a wildcard path for this bus, - * and schedule a rescan. + * Allocate a CCB, create a wildcard path for this bus/target and schedule a rescan. */ ccb = xpt_alloc_ccb_nowait(); if (ccb == NULL) { - isp_prt(isp, ISP_LOGWARN, "unable to alloc CCB for rescan"); + isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan); return; } - if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, - cam_sim_path(isp->isp_sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan"); xpt_free_ccb(ccb); return; @@ -2040,20 +3866,19 @@ isp_make_here(ispsoftc_t *isp, int tgt) } static void -isp_make_gone(ispsoftc_t *isp, int tgt) +isp_make_gone(ispsoftc_t *isp, int chan, int tgt) { struct cam_path *tp; - if (xpt_create_path(&tp, NULL, cam_sim_path(isp->isp_sim), tgt, - CAM_LUN_WILDCARD) == CAM_REQ_CMP) { + struct isp_fc *fc = ISP_FC_PC(isp, chan); + + if (isp_autoconfig == 0) { + return; + } + if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) { xpt_async(AC_LOST_DEVICE, tp, NULL); xpt_free_path(tp); } } -#else -#define isp_make_here(isp, tgt) do { ; } while (0) -#define isp_make_gone(isp, tgt) do { ; } while (0) -#endif - /* * Gone Device Timer Function- when we have decided that a device has gone @@ -2068,19 +3893,20 @@ isp_make_gone(ispsoftc_t *isp, int tgt) static void isp_gdt(void *arg) { - ispsoftc_t *isp = arg; + struct isp_fc *fc = arg; + ispsoftc_t *isp = fc->isp; + int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; int dbidx, tgt, more_to_do = 0; - ISP_LOCK(isp); - isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired"); + isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan); for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - lp = &FCPARAM(isp)->portdb[dbidx]; + lp = &FCPARAM(isp, chan)->portdb[dbidx]; if (lp->state != FC_PORTDB_STATE_ZOMBIE) { continue; } - if (lp->ini_map_idx == 0) { + if (lp->dev_map_idx == 0 || lp->target_mode) { continue; } if (lp->new_reserved == 0) { @@ -2091,23 +3917,20 @@ isp_gdt(void *arg) more_to_do++; continue; } - tgt = lp->ini_map_idx - 1; - FCPARAM(isp)->isp_ini_map[tgt] = 0; - lp->ini_map_idx = 0; + tgt = lp->dev_map_idx - 1; + FCPARAM(isp, chan)->isp_dev_map[tgt] = 0; + lp->dev_map_idx = 0; lp->state = FC_PORTDB_STATE_NIL; - isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt, - "Gone Device Timeout"); - isp_make_gone(isp, tgt); + isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout"); + isp_make_gone(isp, chan, tgt); } if (more_to_do) { - isp->isp_osinfo.gdt_running = 1; - callout_reset(&isp->isp_osinfo.gdt, hz, isp_gdt, isp); + fc->gdt_running = 1; + callout_reset(&fc->gdt, hz, isp_gdt, fc); } else { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "stopping Gone Device Timer"); - isp->isp_osinfo.gdt_running = 0; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan); + fc->gdt_running = 0; } - ISP_UNLOCK(isp); } /* @@ -2122,24 +3945,24 @@ isp_gdt(void *arg) static void isp_ldt(void *arg) { - ispsoftc_t *isp = arg; + struct isp_fc *fc = arg; + ispsoftc_t *isp = fc->isp; + int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; int dbidx, tgt; - ISP_LOCK(isp); - - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime); /* * Notify to the OS all targets who we now consider have departed. */ for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - lp = &FCPARAM(isp)->portdb[dbidx]; + lp = &FCPARAM(isp, chan)->portdb[dbidx]; if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { continue; } - if (lp->ini_map_idx == 0) { + if (lp->dev_map_idx == 0 || lp->target_mode) { continue; } @@ -2159,118 +3982,116 @@ isp_ldt(void *arg) * will happen when loop comes back up. */ - tgt = lp->ini_map_idx - 1; - FCPARAM(isp)->isp_ini_map[tgt] = 0; - lp->ini_map_idx = 0; - isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt, - "Loop Down Timeout"); - isp_make_gone(isp, tgt); + tgt = lp->dev_map_idx - 1; + FCPARAM(isp, chan)->isp_dev_map[tgt] = 0; + lp->dev_map_idx = 0; + lp->state = FC_PORTDB_STATE_NIL; + isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout"); + isp_make_gone(isp, chan, tgt); } /* * The loop down timer has expired. Wake up the kthread * to notice that fact (or make it false). */ - isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1; - wakeup(ISP_KT_WCHAN(isp)); - ISP_UNLOCK(isp); + fc->loop_dead = 1; + fc->loop_down_time = fc->loop_down_limit+1; + wakeup(fc); } static void isp_kthread(void *arg) { - ispsoftc_t *isp = arg; + struct isp_fc *fc = arg; + ispsoftc_t *isp = fc->isp; + int chan = fc - isp->isp_osinfo.pc.fc; int slp = 0; -#if __FreeBSD_version < 500000 - int s = splcam(); -#elif __FreeBSD_version < 700037 - mtx_lock(&Giant); -#else mtx_lock(&isp->isp_osinfo.lock); -#endif - /* - * The first loop is for our usage where we have yet to have - * gotten good fibre channel state. - */ + for (;;) { int wasfrozen, lb, lim; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "isp_kthread: checking FC state"); - isp->isp_osinfo.mbox_sleep_ok = 1; - lb = isp_fc_runstate(isp, 250000); - isp->isp_osinfo.mbox_sleep_ok = 0; - if (lb) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan); + lb = isp_fc_runstate(isp, chan, 250000); + + /* + * Our action is different based upon whether we're supporting + * Initiator mode or not. If we are, we might freeze the simq + * when loop is down and set all sorts of different delays to + * check again. + * + * If not, we simply just wait for loop to come up. + */ + if (lb && (fc->role & ISP_ROLE_INITIATOR)) { /* * Increment loop down time by the last sleep interval */ - isp->isp_osinfo.loop_down_time += slp; + fc->loop_down_time += slp; if (lb < 0) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "kthread: FC loop not up (down count %d)", - isp->isp_osinfo.loop_down_time); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time); } else { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "kthread: FC got to %d (down count %d)", - lb, isp->isp_osinfo.loop_down_time); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC got to %d (down count %d)", __func__, chan, lb, fc->loop_down_time); } - /* * If we've never seen loop up and we've waited longer * than quickboot time, or we've seen loop up but we've * waited longer than loop_down_limit, give up and go * to sleep until loop comes up. */ - if (FCPARAM(isp)->loop_seen_once == 0) { + if (FCPARAM(isp, chan)->loop_seen_once == 0) { lim = isp_quickboot_time; } else { - lim = isp->isp_osinfo.loop_down_limit; + lim = fc->loop_down_limit; } - if (isp->isp_osinfo.loop_down_time >= lim) { - isp_freeze_loopdown(isp, "loop limit hit"); + if (fc->loop_down_time >= lim) { + isp_freeze_loopdown(isp, chan, "loop limit hit"); slp = 0; - } else if (isp->isp_osinfo.loop_down_time < 10) { + } else if (fc->loop_down_time < 10) { slp = 1; - } else if (isp->isp_osinfo.loop_down_time < 30) { + } else if (fc->loop_down_time < 30) { slp = 5; - } else if (isp->isp_osinfo.loop_down_time < 60) { + } else if (fc->loop_down_time < 60) { slp = 10; - } else if (isp->isp_osinfo.loop_down_time < 120) { + } else if (fc->loop_down_time < 120) { slp = 20; } else { slp = 30; } + } else if (lb) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan); + fc->loop_down_time += slp; + slp = 60; } else { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "isp_kthread: FC state OK"); - isp->isp_osinfo.loop_down_time = 0; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan); + fc->loop_down_time = 0; slp = 0; } + /* - * If we'd frozen the simq, unfreeze it now so that CAM - * can start sending us commands. If the FC state isn't - * okay yet, they'll hit that in isp_start which will - * freeze the queue again. + * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it + * now so that CAM can start sending us commands. + * + * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again + * or kill the commands, as appropriate. */ - wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN; - isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; - if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "isp_kthread: releasing simq"); - xpt_release_simq(isp->isp_sim, 1); + + if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) { + wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; + fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; + if (wasfrozen && fc->simqfrozen == 0) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); + xpt_release_simq(fc->sim, 1); + } } - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "isp_kthread: sleep time %d", slp); -#if __FreeBSD_version < 700037 - tsleep(ISP_KT_WCHAN(isp), PRIBIO, "ispf", slp * hz); -#else - msleep(ISP_KT_WCHAN(isp), &isp->isp_osinfo.lock, - PRIBIO, "ispf", slp * hz); -#endif + + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp); + + msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz); + /* * If slp is zero, we're waking up for the first time after * things have been okay. In this case, we set a deferral state @@ -2278,42 +4099,14 @@ isp_kthread(void *arg) * the FC state evaluation. This gives the loop/fabric a chance * to settle. */ - if (slp == 0 && isp->isp_osinfo.hysteresis) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "isp_kthread: sleep hysteresis tick time %d", - isp->isp_osinfo.hysteresis * hz); -#if __FreeBSD_version < 700037 - (void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT", - (isp->isp_osinfo.hysteresis * hz)); -#else - (void) msleep(&isp_fabric_hysteresis, - &isp->isp_osinfo.lock, PRIBIO, "ispT", - (isp->isp_osinfo.hysteresis * hz)); -#endif + if (slp == 0 && fc->hysteresis) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz); + (void) msleep(&isp_fabric_hysteresis, &isp->isp_osinfo.lock, PRIBIO, "ispT", (fc->hysteresis * hz)); } } -#if __FreeBSD_version < 500000 - splx(s); -#elif __FreeBSD_version < 700037 - mtx_unlock(&Giant); -#else mtx_unlock(&isp->isp_osinfo.lock); -#endif } -#if __FreeBSD_version < 500000 -static void isp_action_wrk(struct cam_sim *, union ccb *); -static void -isp_action(struct cam_sim *sim, union ccb *ccb) -{ - ispsoftc_t *isp = (ispsoftc_t *)cam_sim_softc(sim); - ISP_LOCK(isp); - isp_action_wrk(sim, ccb); - ISP_UNLOCK(isp); -} -#define isp_action isp_action_wrk -#endif - static void isp_action(struct cam_sim *sim, union ccb *ccb) { @@ -2324,8 +4117,9 @@ isp_action(struct cam_sim *sim, union ccb *ccb) CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); isp = (ispsoftc_t *)cam_sim_softc(sim); - if (isp->isp_state != ISP_RUNSTATE && - ccb->ccb_h.func_code == XPT_SCSI_IO) { + mtx_assert(&isp->isp_lock, MA_OWNED); + + if (isp->isp_state != ISP_RUNSTATE && ccb->ccb_h.func_code == XPT_SCSI_IO) { isp_init(isp); if (isp->isp_state != ISP_INITSTATE) { /* @@ -2343,6 +4137,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: /* Execute the requested I/O operation */ + bus = XS_CHANNEL(ccb); /* * Do a couple of preliminary checks... */ @@ -2370,8 +4165,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) if (isp_get_pcmd(isp, ccb)) { isp_prt(isp, ISP_LOGWARN, "out of PCMDs"); cam_freeze_devq(ccb->ccb_h.path); - cam_release_devq(ccb->ccb_h.path, - RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0); xpt_done(ccb); break; } @@ -2388,54 +4182,48 @@ isp_action(struct cam_sim *sim, union ccb *ccb) ts = 60*1000; } ts = isp_mstohz(ts); - callout_reset(&PISP_PCMD(ccb)->wdog, ts, - isp_watchdog, ccb); + callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb); break; case CMD_RQLATER: /* - * Handle initial and subsequent loop down cases + * We get this result for FC devices if the loop state isn't ready yet + * or if the device in question has gone zombie on us. + * + * If we've never seen Loop UP at all, we requeue this request and wait + * for the initial loop up delay to expire. */ - if (FCPARAM(isp)->loop_seen_once == 0) { - lim = isp_quickboot_time; - } else { - lim = isp->isp_osinfo.loop_down_limit; - } - if (isp->isp_osinfo.loop_down_time >= lim) { - isp_prt(isp, ISP_LOGDEBUG0, - "%d.%d downtime (%d) > lim (%d)", - XS_TGT(ccb), XS_LUN(ccb), - isp->isp_osinfo.loop_down_time, lim); - ccb->ccb_h.status = - CAM_SEL_TIMEOUT|CAM_DEV_QFRZN; + lim = ISP_FC_PC(isp, bus)->loop_down_limit; + if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) { + if (FCPARAM(isp, bus)->loop_seen_once == 0) { + isp_prt(isp, ISP_LOGDEBUG0, "%d.%d loop not seen yet @ %lu", XS_TGT(ccb), XS_LUN(ccb), (unsigned long) time_uptime); + } else { + isp_prt(isp, ISP_LOGDEBUG0, "%d.%d downtime (%d) > lim (%d)", XS_TGT(ccb), XS_LUN(ccb), ISP_FC_PC(isp, bus)->loop_down_time, lim); + } + ccb->ccb_h.status = CAM_SEL_TIMEOUT|CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, 1); isp_free_pcmd(isp, ccb); xpt_done(ccb); break; } - isp_prt(isp, ISP_LOGDEBUG0, - "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb)); - /* - * Otherwise, retry in a while. - */ + isp_prt(isp, ISP_LOGDEBUG0, "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb)); cam_freeze_devq(ccb->ccb_h.path); - cam_release_devq(ccb->ccb_h.path, - RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); XS_SETERR(ccb, CAM_REQUEUE_REQ); isp_free_pcmd(isp, ccb); xpt_done(ccb); break; case CMD_EAGAIN: - XS_SETERR(ccb, CAM_REQUEUE_REQ); isp_free_pcmd(isp, ccb); + cam_freeze_devq(ccb->ccb_h.path); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0); + XS_SETERR(ccb, CAM_REQUEUE_REQ); xpt_done(ccb); break; case CMD_COMPLETE: isp_done((struct ccb_scsiio *) ccb); break; default: - isp_prt(isp, ISP_LOGERR, - "What's this? 0x%x at %d in file %s", - error, __LINE__, __FILE__); + isp_prt(isp, ISP_LOGERR, "What's this? 0x%x at %d in file %s", error, __LINE__, __FILE__); XS_SETERR(ccb, CAM_REQ_CMP_ERR); isp_free_pcmd(isp, ccb); xpt_done(ccb); @@ -2443,33 +4231,34 @@ isp_action(struct cam_sim *sim, union ccb *ccb) break; #ifdef ISP_TARGET_MODE - case XPT_EN_LUN: /* Enable LUN as a target */ - { - int seq, i; - seq = isp_en_lun(isp, ccb); - if (seq < 0) { - xpt_done(ccb); - break; - } - for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) { - uint32_t isr; - uint16_t sema, mbox; - if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { - isp_intr(isp, isr, sema, mbox); - } - DELAY(1000); + case XPT_EN_LUN: /* Enable/Disable LUN as a target */ + if (ccb->cel.enable) { + isp_enable_lun(isp, ccb); + } else { + isp_disable_lun(isp, ccb); } break; - } - case XPT_NOTIFY_ACK: /* recycle notify ack */ - case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ + case XPT_IMMEDIATE_NOTIFY: /* Add Immediate Notify Resource */ case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ { - tstate_t *tptr = - get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); + tstate_t *tptr = get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun); if (tptr == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - xpt_done(ccb); + tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD); + } + if (tptr == NULL) { + const char *str; + uint32_t tag; + + if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { + str = "XPT_IMMEDIATE_NOTIFY"; + tag = ccb->cin1.seq_id; + } else { + tag = ccb->atio.tag_id; + str = "XPT_ACCEPT_TARGET_IO"; + } + ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] no state pointer found for %s\n", __func__, tag, str); + dump_tstates(isp, XS_CHANNEL(ccb)); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; break; } ccb->ccb_h.sim_priv.entries[0].field = 0; @@ -2477,35 +4266,70 @@ isp_action(struct cam_sim *sim, union ccb *ccb) ccb->ccb_h.flags = 0; if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { - /* - * Note that the command itself may not be done- - * it may not even have had the first CTIO sent. - */ + if (ccb->atio.tag_id) { + atio_private_data_t *atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id); + if (atp) { + isp_put_atpd(isp, tptr, atp); + } + } tptr->atio_count++; - isp_prt(isp, ISP_LOGTDEBUG0, - "Put FREE ATIO, lun %d, count now %d", - ccb->ccb_h.target_lun, tptr->atio_count); - SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, - sim_links.sle); - } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { + SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n", + ((struct ccb_accept_tio *)ccb)->tag_id, tptr->atio_count); + } else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) { + if (ccb->cin1.tag_id) { + inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id); + if (ntp) { + isp_put_ntpd(isp, tptr, ntp); + } + } tptr->inot_count++; - isp_prt(isp, ISP_LOGTDEBUG0, - "Put FREE INOT, lun %d, count now %d", - ccb->ccb_h.target_lun, tptr->inot_count); - SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, - sim_links.sle); - } else { - isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");; + SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle); + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n", + ((struct ccb_immediate_notify *)ccb)->seq_id, tptr->inot_count); } rls_lun_statep(isp, tptr); ccb->ccb_h.status = CAM_REQ_INPROG; break; } - case XPT_CONT_TARGET_IO: + case XPT_NOTIFY_ACKNOWLEDGE: /* notify ack */ { - isp_target_start_ctio(isp, ccb); + tstate_t *tptr; + inot_private_data_t *ntp; + + /* + * XXX: Because we cannot guarantee that the path information in the notify acknowledge ccb + * XXX: matches that for the immediate notify, we have to *search* for the notify structure + */ + /* + * All the relevant path information is in the associated immediate notify + */ + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] NOTIFY ACKNOWLEDGE for 0x%x seen\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id); + ntp = get_ntp_from_tagdata(isp, ccb->cna2.tag_id, ccb->cna2.seq_id, &tptr); + if (ntp == NULL) { + ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] XPT_NOTIFY_ACKNOWLEDGE of 0x%x cannot find ntp private data\n", __func__, + ccb->cna2.tag_id, ccb->cna2.seq_id); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + xpt_done(ccb); + break; + } + if (isp_handle_platform_target_notify_ack(isp, &ntp->rd.nt)) { + rls_lun_statep(isp, tptr); + cam_freeze_devq(ccb->ccb_h.path); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0); + XS_SETERR(ccb, CAM_REQUEUE_REQ); + break; + } + isp_put_ntpd(isp, tptr, ntp); + rls_lun_statep(isp, tptr); + ccb->ccb_h.status = CAM_REQ_CMP; + ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] calling xpt_done for tag 0x%x\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id); + xpt_done(ccb); break; } + case XPT_CONT_TARGET_IO: + isp_target_start_ctio(isp, ccb); + break; #endif case XPT_RESET_DEV: /* BDR the specified SCSI device */ @@ -2513,7 +4337,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) tgt = ccb->ccb_h.target_id; tgt |= (bus << 16); - error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); + error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt); if (error) { ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else { @@ -2527,12 +4351,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) switch (accb->ccb_h.func_code) { #ifdef ISP_TARGET_MODE case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: - ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb); - break; - case XPT_CONT_TARGET_IO: - isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet"); - ccb->ccb_h.status = CAM_UA_ABORT; + isp_target_mark_aborted(isp, accb); break; #endif case XPT_SCSI_IO: @@ -2550,11 +4369,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) xpt_done(ccb); break; } -#ifdef CAM_NEW_TRAN_CODE #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) -#else -#define IS_CURRENT_SETTINGS(c) (c->flags & CCB_TRANS_CURRENT_SETTINGS) -#endif case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ cts = &ccb->cts; if (!IS_CURRENT_SETTINGS(cts)) { @@ -2563,72 +4378,11 @@ isp_action(struct cam_sim *sim, union ccb *ccb) break; } tgt = cts->ccb_h.target_id; + bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); if (IS_SCSI(isp)) { -#ifndef CAM_NEW_TRAN_CODE - sdparam *sdp = isp->isp_param; - uint16_t *dptr; - - bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); - - sdp += bus; - /* - * We always update (internally) from goal_flags - * so any request to change settings just gets - * vectored to that location. - */ - dptr = &sdp->isp_devparam[tgt].goal_flags; - - /* - * Note that these operations affect the - * the goal flags (goal_flags)- not - * the current state flags. Then we mark - * things so that the next operation to - * this HBA will cause the update to occur. - */ - if (cts->valid & CCB_TRANS_DISC_VALID) { - if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { - *dptr |= DPARM_DISC; - } else { - *dptr &= ~DPARM_DISC; - } - } - if (cts->valid & CCB_TRANS_TQ_VALID) { - if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { - *dptr |= DPARM_TQING; - } else { - *dptr &= ~DPARM_TQING; - } - } - if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { - switch (cts->bus_width) { - case MSG_EXT_WDTR_BUS_16_BIT: - *dptr |= DPARM_WIDE; - break; - default: - *dptr &= ~DPARM_WIDE; - } - } - /* - * Any SYNC RATE of nonzero and SYNC_OFFSET - * of nonzero will cause us to go to the - * selected (from NVRAM) maximum value for - * this device. At a later point, we'll - * allow finer control. - */ - if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && - (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && - (cts->sync_offset > 0)) { - *dptr |= DPARM_SYNC; - } else { - *dptr &= ~DPARM_SYNC; - } - *dptr |= DPARM_SAFE_DFLT; -#else - struct ccb_trans_settings_scsi *scsi = - &cts->proto_specific.scsi; - struct ccb_trans_settings_spi *spi = - &cts->xport_specific.spi; - sdparam *sdp = isp->isp_param; + struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; + struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; + sdparam *sdp = SDPARAM(isp, bus); uint16_t *dptr; if (spi->valid == 0 && scsi->valid == 0) { @@ -2636,9 +4390,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) xpt_done(ccb); break; } - - bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); - sdp += bus; + /* * We always update (internally) from goal_flags * so any request to change settings just gets @@ -2670,29 +4422,20 @@ isp_action(struct cam_sim *sim, union ccb *ccb) /* * XXX: FIX ME */ - if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && - (spi->valid & CTS_SPI_VALID_SYNC_RATE) && - (spi->sync_period && spi->sync_offset)) { + if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && (spi->valid & CTS_SPI_VALID_SYNC_RATE) && (spi->sync_period && spi->sync_offset)) { *dptr |= DPARM_SYNC; /* * XXX: CHECK FOR LEGALITY */ - sdp->isp_devparam[tgt].goal_period = - spi->sync_period; - sdp->isp_devparam[tgt].goal_offset = - spi->sync_offset; + sdp->isp_devparam[tgt].goal_period = spi->sync_period; + sdp->isp_devparam[tgt].goal_offset = spi->sync_offset; } else { *dptr &= ~DPARM_SYNC; } -#endif - isp_prt(isp, ISP_LOGDEBUG0, - "SET (%d.%d.%d) to flags %x off %x per %x", - bus, tgt, cts->ccb_h.target_lun, - sdp->isp_devparam[tgt].goal_flags, - sdp->isp_devparam[tgt].goal_offset, - sdp->isp_devparam[tgt].goal_period); + isp_prt(isp, ISP_LOGDEBUG0, "SET (%d.%d.%d) to flags %x off %x per %x", bus, tgt, cts->ccb_h.target_lun, sdp->isp_devparam[tgt].goal_flags, + sdp->isp_devparam[tgt].goal_offset, sdp->isp_devparam[tgt].goal_period); sdp->isp_devparam[tgt].dev_update = 1; - isp->isp_update |= (1 << bus); + sdp->update = 1; } ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); @@ -2700,27 +4443,11 @@ isp_action(struct cam_sim *sim, union ccb *ccb) case XPT_GET_TRAN_SETTINGS: cts = &ccb->cts; tgt = cts->ccb_h.target_id; + bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); if (IS_FC(isp)) { -#ifndef CAM_NEW_TRAN_CODE - /* - * a lot of normal SCSI things don't make sense. - */ - cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; - cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; - /* - * How do you measure the width of a high - * speed serial bus? Well, in bytes. - * - * Offset and period make no sense, though, so we set - * (above) a 'base' transfer speed to be gigabit. - */ - cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; -#else - fcparam *fcp = isp->isp_param; - struct ccb_trans_settings_scsi *scsi = - &cts->proto_specific.scsi; - struct ccb_trans_settings_fc *fc = - &cts->xport_specific.fc; + fcparam *fcp = FCPARAM(isp, bus); + struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; + struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc; cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_2; @@ -2731,35 +4458,24 @@ isp_action(struct cam_sim *sim, union ccb *ccb) scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; fc->valid = CTS_FC_VALID_SPEED; fc->bitrate = 100000; - if (fcp->isp_gbspeed == 4 || fcp->isp_gbspeed == 2) - fc->bitrate *= fcp->isp_gbspeed; + fc->bitrate *= fcp->isp_gbspeed; if (tgt > 0 && tgt < MAX_FC_TARG) { fcportdb_t *lp = &fcp->portdb[tgt]; fc->wwnn = lp->node_wwn; fc->wwpn = lp->port_wwn; fc->port = lp->portid; - fc->valid |= CTS_FC_VALID_WWNN | - CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; + fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT; } -#endif } else { -#ifdef CAM_NEW_TRAN_CODE - struct ccb_trans_settings_scsi *scsi = - &cts->proto_specific.scsi; - struct ccb_trans_settings_spi *spi = - &cts->xport_specific.spi; -#endif - sdparam *sdp = isp->isp_param; - int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); + struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; + struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; + sdparam *sdp = SDPARAM(isp, bus); uint16_t dval, pval, oval; - sdp += bus; - if (IS_CURRENT_SETTINGS(cts)) { sdp->isp_devparam[tgt].dev_refresh = 1; - isp->isp_update |= (1 << bus); - (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, - NULL); + sdp->update = 1; + (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus); dval = sdp->isp_devparam[tgt].actv_flags; oval = sdp->isp_devparam[tgt].actv_offset; pval = sdp->isp_devparam[tgt].actv_period; @@ -2769,31 +4485,6 @@ isp_action(struct cam_sim *sim, union ccb *ccb) pval = sdp->isp_devparam[tgt].nvrm_period; } -#ifndef CAM_NEW_TRAN_CODE - cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); - - if (dval & DPARM_DISC) { - cts->flags |= CCB_TRANS_DISC_ENB; - } - if (dval & DPARM_TQING) { - cts->flags |= CCB_TRANS_TAG_ENB; - } - if (dval & DPARM_WIDE) { - cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; - } else { - cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; - } - cts->valid = CCB_TRANS_BUS_WIDTH_VALID | - CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; - - if ((dval & DPARM_SYNC) && oval != 0) { - cts->sync_period = pval; - cts->sync_offset = oval; - cts->valid |= - CCB_TRANS_SYNC_RATE_VALID | - CCB_TRANS_SYNC_OFFSET_VALID; - } -#else cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_2; cts->transport = XPORT_SPI; @@ -2828,10 +4519,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) } spi->valid |= CTS_SPI_VALID_DISC; } -#endif - isp_prt(isp, ISP_LOGDEBUG0, - "GET %s (%d.%d.%d) to flags %x off %x per %x", - IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", + isp_prt(isp, ISP_LOGDEBUG0, "GET %s (%d.%d.%d) to flags %x off %x per %x", IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM", bus, tgt, cts->ccb_h.target_lun, dval, oval, pval); } ccb->ccb_h.status = CAM_REQ_CMP; @@ -2839,62 +4527,133 @@ isp_action(struct cam_sim *sim, union ccb *ccb) break; case XPT_CALC_GEOMETRY: -#if __FreeBSD_version < 500000 - { - struct ccb_calc_geometry *ccg; - u_int32_t secs_per_cylinder; - u_int32_t size_mb; + cam_calc_geometry(&ccb->ccg, 1); + xpt_done(ccb); + break; - ccg = &ccb->ccg; - if (ccg->block_size == 0) { - ccb->ccb_h.status = CAM_REQ_INVALID; + case XPT_RESET_BUS: /* Reset the specified bus */ + bus = cam_sim_bus(sim); + error = isp_control(isp, ISPCTL_RESET_BUS, bus); + if (error) { + ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); break; } - size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); - if (size_mb > 1024) { - ccg->heads = 255; - ccg->secs_per_track = 63; + if (bootverbose) { + xpt_print(ccb->ccb_h.path, "reset bus on channel %d\n", bus); + } + if (IS_FC(isp)) { + xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, 0); } else { - ccg->heads = 64; - ccg->secs_per_track = 32; + xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, 0); } - secs_per_cylinder = ccg->heads * ccg->secs_per_track; - ccg->cylinders = ccg->volume_size / secs_per_cylinder; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; - } -#else - { - cam_calc_geometry(&ccb->ccg, /*extended*/1); - xpt_done(ccb); - break; - } -#endif - case XPT_RESET_BUS: /* Reset the specified bus */ - bus = cam_sim_bus(sim); - error = isp_control(isp, ISPCTL_RESET_BUS, &bus); - if (error) - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - else { - if (bootverbose) { - xpt_print(ccb->ccb_h.path, "reset bus\n"); - } - if (cam_sim_bus(sim) && isp->isp_path2 != NULL) - xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); - else if (isp->isp_path != NULL) - xpt_async(AC_BUS_RESET, isp->isp_path, NULL); - ccb->ccb_h.status = CAM_REQ_CMP; - } - xpt_done(ccb); - break; case XPT_TERM_IO: /* Terminate the I/O process */ ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; + case XPT_SET_SIM_KNOB: /* Set SIM knobs */ + { + struct ccb_sim_knob *kp = &ccb->knob; + fcparam *fcp; + + + if (!IS_FC(isp)) { + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + } + + bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path)); + fcp = FCPARAM(isp, bus); + + if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) { + fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn; + fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn; +isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn); + } + ccb->ccb_h.status = CAM_REQ_CMP; + if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) { + int rchange = 0; + int newrole = 0; + + switch (kp->xport_specific.fc.role) { + case KNOB_ROLE_NONE: + if (fcp->role != ISP_ROLE_NONE) { + rchange = 1; + newrole = ISP_ROLE_NONE; + } + break; + case KNOB_ROLE_TARGET: + if (fcp->role != ISP_ROLE_TARGET) { + rchange = 1; + newrole = ISP_ROLE_TARGET; + } + break; + case KNOB_ROLE_INITIATOR: + if (fcp->role != ISP_ROLE_INITIATOR) { + rchange = 1; + newrole = ISP_ROLE_INITIATOR; + } + break; + case KNOB_ROLE_BOTH: + if (fcp->role != ISP_ROLE_BOTH) { + rchange = 1; + newrole = ISP_ROLE_BOTH; + } + break; + } + if (rchange) { + if (isp_fc_change_role(isp, bus, newrole) != 0) { + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#ifdef ISP_TARGET_MODE + } else if (newrole == ISP_ROLE_TARGET || newrole == ISP_ROLE_BOTH) { + isp_enable_deferred_luns(isp, bus); +#endif + } + } + } + xpt_done(ccb); + break; + } + case XPT_GET_SIM_KNOB: /* Set SIM knobs */ + { + struct ccb_sim_knob *kp = &ccb->knob; + + if (IS_FC(isp)) { + fcparam *fcp; + + bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path)); + fcp = FCPARAM(isp, bus); + + kp->xport_specific.fc.wwnn = fcp->isp_wwnn; + kp->xport_specific.fc.wwpn = fcp->isp_wwpn; + switch (fcp->role) { + case ISP_ROLE_NONE: + kp->xport_specific.fc.role = KNOB_ROLE_NONE; + break; + case ISP_ROLE_TARGET: + kp->xport_specific.fc.role = KNOB_ROLE_TARGET; + break; + case ISP_ROLE_INITIATOR: + kp->xport_specific.fc.role = KNOB_ROLE_INITIATOR; + break; + case ISP_ROLE_BOTH: + kp->xport_specific.fc.role = KNOB_ROLE_BOTH; + break; + } + kp->xport_specific.fc.valid = KNOB_VALID_ADDRESS | KNOB_VALID_ROLE; + ccb->ccb_h.status = CAM_REQ_CMP; + } else { + ccb->ccb_h.status = CAM_REQ_INVALID; + } + xpt_done(ccb); + break; + } case XPT_PATH_INQ: /* Path routing inquiry */ { struct ccb_pathinq *cpi = &ccb->cpi; @@ -2909,8 +4668,12 @@ isp_action(struct cam_sim *sim, union ccb *ccb) cpi->max_target = ISP_MAX_TARGETS(isp) - 1; cpi->max_lun = ISP_MAX_LUNS(isp) - 1; cpi->bus_id = cam_sim_bus(sim); + bus = cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); if (IS_FC(isp)) { + fcparam *fcp = FCPARAM(isp, bus); + cpi->hba_misc = PIM_NOBUSRESET; + /* * Because our loop ID can shift from time to time, * make our initiator ID out of range of our bus. @@ -2918,37 +4681,33 @@ isp_action(struct cam_sim *sim, union ccb *ccb) cpi->initiator_id = cpi->max_target + 1; /* - * Set base transfer capabilities for Fibre Channel. - * Technically not correct because we don't know - * what media we're running on top of- but we'll - * look good if we always say 100MB/s. + * Set base transfer capabilities for Fibre Channel, for this HBA. */ - cpi->base_transfer_speed = 100000; - if (FCPARAM(isp)->isp_gbspeed == 4 || - FCPARAM(isp)->isp_gbspeed == 2) - cpi->base_transfer_speed *= - FCPARAM(isp)->isp_gbspeed; + if (IS_24XX(isp)) { + cpi->base_transfer_speed = 4000000; + } else if (IS_23XX(isp)) { + cpi->base_transfer_speed = 2000000; + } else { + cpi->base_transfer_speed = 1000000; + } cpi->hba_inquiry = PI_TAG_ABLE; -#ifdef CAM_NEW_TRAN_CODE cpi->transport = XPORT_FC; cpi->transport_version = 0; -#endif + cpi->xport_specific.fc.wwnn = fcp->isp_wwnn; + cpi->xport_specific.fc.wwpn = fcp->isp_wwpn; + cpi->xport_specific.fc.port = fcp->isp_portid; + cpi->xport_specific.fc.bitrate = fcp->isp_gbspeed * 1000; } else { - sdparam *sdp = isp->isp_param; - sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); + sdparam *sdp = SDPARAM(isp, bus); cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; cpi->hba_misc = 0; cpi->initiator_id = sdp->isp_initiator_id; cpi->base_transfer_speed = 3300; -#ifdef CAM_NEW_TRAN_CODE cpi->transport = XPORT_SPI; cpi->transport_version = 2; -#endif } -#ifdef CAM_NEW_TRAN_CODE cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_2; -#endif strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); @@ -2967,18 +4726,16 @@ isp_action(struct cam_sim *sim, union ccb *ccb) #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) void -isp_done(struct ccb_scsiio *sccb) +isp_done(XS_T *sccb) { ispsoftc_t *isp = XS_ISP(sccb); if (XS_NOERR(sccb)) XS_SETERR(sccb, CAM_REQ_CMP); - if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && - (sccb->scsi_status != SCSI_STATUS_OK)) { + if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && (sccb->scsi_status != SCSI_STATUS_OK)) { sccb->ccb_h.status &= ~CAM_STATUS_MASK; - if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && - (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { + if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) { sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; } else { sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; @@ -2987,78 +4744,58 @@ isp_done(struct ccb_scsiio *sccb) sccb->ccb_h.status &= ~CAM_SIM_QUEUED; if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - isp_prt(isp, ISP_LOGDEBUG0, - "target %d lun %d CAM status 0x%x SCSI status 0x%x", - XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, - sccb->scsi_status); + isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { sccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(sccb->ccb_h.path, 1); } } - if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && - (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - xpt_print(sccb->ccb_h.path, - "cam completion status 0x%x\n", sccb->ccb_h.status); + if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + xpt_print(sccb->ccb_h.path, "cam completion status 0x%x\n", sccb->ccb_h.status); } XS_CMD_S_DONE(sccb); - if (XS_CMD_WDOG_P(sccb) == 0) { - callout_stop(&PISP_PCMD(sccb)->wdog); - if (XS_CMD_GRACE_P(sccb)) { - isp_prt(isp, ISP_LOGDEBUG2, - "finished command on borrowed time"); - } - XS_CMD_S_CLEAR(sccb); - isp_free_pcmd(isp, (union ccb *) sccb); - xpt_done((union ccb *) sccb); - } + callout_stop(&PISP_PCMD(sccb)->wdog); + XS_CMD_S_CLEAR(sccb); + isp_free_pcmd(isp, (union ccb *) sccb); + xpt_done((union ccb *) sccb); } -int -isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) +void +isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) { - int bus, rv = 0; - static const char prom[] = - "PortID 0x%06x handle 0x%x role %s %s\n" - " WWNN 0x%08x%08x WWPN 0x%08x%08x"; - static const char prom2[] = - "PortID 0x%06x handle 0x%x role %s %s tgt %u\n" - " WWNN 0x%08x%08x WWPN 0x%08x%08x"; + int bus; + static const char prom[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s WWPN 0x%08x%08x"; + static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s tgt %u WWPN 0x%08x%08x"; char *msg = NULL; target_id_t tgt; fcportdb_t *lp; struct cam_path *tmppath; + va_list ap; switch (cmd) { case ISPASYNC_NEW_TGT_PARAMS: { -#ifdef CAM_NEW_TRAN_CODE struct ccb_trans_settings_scsi *scsi; struct ccb_trans_settings_spi *spi; -#endif int flags, tgt; - sdparam *sdp = isp->isp_param; + sdparam *sdp; struct ccb_trans_settings cts; memset(&cts, 0, sizeof (struct ccb_trans_settings)); - tgt = *((int *)arg); - bus = (tgt >> 16) & 0xffff; - tgt &= 0xffff; - sdp += bus; - if (xpt_create_path(&tmppath, NULL, - cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), - tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { - isp_prt(isp, ISP_LOGWARN, - "isp_async cannot make temp path for %d.%d", - tgt, bus); - rv = -1; + va_start(ap, cmd); + bus = va_arg(ap, int); + tgt = va_arg(ap, int); + va_end(ap); + sdp = SDPARAM(isp, bus); + + if (xpt_create_path(&tmppath, NULL, cam_sim_path(ISP_SPI_PC(isp, bus)->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + isp_prt(isp, ISP_LOGWARN, "isp_async cannot make temp path for %d.%d", tgt, bus); break; } flags = sdp->isp_devparam[tgt].actv_flags; -#ifdef CAM_NEW_TRAN_CODE cts.type = CTS_TYPE_CURRENT_SETTINGS; cts.protocol = PROTO_SCSI; cts.transport = XPORT_SPI; @@ -3087,45 +4824,25 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) spi->sync_period = sdp->isp_devparam[tgt].actv_period; spi->sync_offset = sdp->isp_devparam[tgt].actv_offset; } -#else - cts.flags = CCB_TRANS_CURRENT_SETTINGS; - cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; - if (flags & DPARM_DISC) { - cts.flags |= CCB_TRANS_DISC_ENB; - } - if (flags & DPARM_TQING) { - cts.flags |= CCB_TRANS_TAG_ENB; - } - cts.valid |= CCB_TRANS_BUS_WIDTH_VALID; - cts.bus_width = (flags & DPARM_WIDE)? - MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; - cts.sync_period = sdp->isp_devparam[tgt].actv_period; - cts.sync_offset = sdp->isp_devparam[tgt].actv_offset; - if (flags & DPARM_SYNC) { - cts.valid |= - CCB_TRANS_SYNC_RATE_VALID | - CCB_TRANS_SYNC_OFFSET_VALID; - } -#endif - isp_prt(isp, ISP_LOGDEBUG2, - "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", - bus, tgt, sdp->isp_devparam[tgt].actv_period, - sdp->isp_devparam[tgt].actv_offset, flags); + isp_prt(isp, ISP_LOGDEBUG2, "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", bus, tgt, sdp->isp_devparam[tgt].actv_period, sdp->isp_devparam[tgt].actv_offset, flags); xpt_setup_ccb(&cts.ccb_h, tmppath, 1); xpt_async(AC_TRANSFER_NEG, tmppath, &cts); xpt_free_path(tmppath); break; } case ISPASYNC_BUS_RESET: - bus = *((int *)arg); - isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", - bus); - if (bus > 0 && isp->isp_path2) { - xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); - } else if (isp->isp_path) { - xpt_async(AC_BUS_RESET, isp->isp_path, NULL); + { + va_start(ap, cmd); + bus = va_arg(ap, int); + va_end(ap); + isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", bus); + if (IS_FC(isp)) { + xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, NULL); + } else { + xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, NULL); } break; + } case ISPASYNC_LIP: if (msg == NULL) { msg = "LIP Received"; @@ -3137,144 +4854,134 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) } /* FALLTHROUGH */ case ISPASYNC_LOOP_DOWN: + { + struct isp_fc *fc; if (msg == NULL) { msg = "LOOP Down"; } - if (isp->isp_path) { - isp_freeze_loopdown(isp, msg); + va_start(ap, cmd); + bus = va_arg(ap, int); + va_end(ap); + + FCPARAM(isp, bus)->link_active = 1; + + fc = ISP_FC_PC(isp, bus); + /* + * We don't do any simq freezing if we are only in target mode + */ + if (fc->role & ISP_ROLE_INITIATOR) { + if (fc->path) { + isp_freeze_loopdown(isp, bus, msg); + } + if (fc->ldt_running == 0) { + fc->ldt_running = 1; + callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime); + } } - if (isp->isp_osinfo.ldt_running == 0) { - isp->isp_osinfo.ldt_running = 1; - callout_reset(&isp->isp_osinfo.ldt, - isp->isp_osinfo.loop_down_limit * hz, isp_ldt, isp); - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "starting Loop Down Timer"); - } - isp_prt(isp, ISP_LOGINFO, msg); + isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg); break; + } case ISPASYNC_LOOP_UP: + va_start(ap, cmd); + bus = va_arg(ap, int); + va_end(ap); /* * Now we just note that Loop has come up. We don't * actually do anything because we're waiting for a * Change Notify before activating the FC cleanup * thread to look at the state of the loop again. */ - isp_prt(isp, ISP_LOGINFO, "Loop UP"); + FCPARAM(isp, bus)->link_active = 1; + ISP_FC_PC(isp, bus)->loop_dead = 0; + ISP_FC_PC(isp, bus)->loop_down_time = 0; + isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus); break; case ISPASYNC_DEV_ARRIVED: - lp = arg; + va_start(ap, cmd); + bus = va_arg(ap, int); + lp = va_arg(ap, fcportdb_t *); + va_end(ap); lp->reserved = 0; - if ((isp->isp_role & ISP_ROLE_INITIATOR) && - (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) { - int dbidx = lp - FCPARAM(isp)->portdb; + if ((ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) { + int dbidx = lp - FCPARAM(isp, bus)->portdb; int i; for (i = 0; i < MAX_FC_TARG; i++) { if (i >= FL_ID && i <= SNS_ID) { continue; } - if (FCPARAM(isp)->isp_ini_map[i] == 0) { + if (FCPARAM(isp, bus)->isp_dev_map[i] == 0) { break; } } if (i < MAX_FC_TARG) { - FCPARAM(isp)->isp_ini_map[i] = dbidx + 1; - lp->ini_map_idx = i + 1; + FCPARAM(isp, bus)->isp_dev_map[i] = dbidx + 1; + lp->dev_map_idx = i + 1; } else { isp_prt(isp, ISP_LOGWARN, "out of target ids"); - isp_dump_portdb(isp); + isp_dump_portdb(isp, bus); } } - if (lp->ini_map_idx) { - tgt = lp->ini_map_idx - 1; - isp_prt(isp, ISP_LOGCONFIG, prom2, - lp->portid, lp->handle, - roles[lp->roles], "arrived at", tgt, - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); - isp_make_here(isp, tgt); + if (lp->dev_map_idx) { + tgt = lp->dev_map_idx - 1; + isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "arrived at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); + isp_make_here(isp, bus, tgt); } else { - isp_prt(isp, ISP_LOGCONFIG, prom, - lp->portid, lp->handle, - roles[lp->roles], "arrived", - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "arrived", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } break; case ISPASYNC_DEV_CHANGED: - lp = arg; + va_start(ap, cmd); + bus = va_arg(ap, int); + lp = va_arg(ap, fcportdb_t *); + va_end(ap); + lp->reserved = 0; if (isp_change_is_bad) { lp->state = FC_PORTDB_STATE_NIL; - if (lp->ini_map_idx) { - tgt = lp->ini_map_idx - 1; - FCPARAM(isp)->isp_ini_map[tgt] = 0; - lp->ini_map_idx = 0; - isp_prt(isp, ISP_LOGCONFIG, prom3, - lp->portid, tgt, "change is bad"); - isp_make_gone(isp, tgt); + if (lp->dev_map_idx) { + tgt = lp->dev_map_idx - 1; + FCPARAM(isp, bus)->isp_dev_map[tgt] = 0; + lp->dev_map_idx = 0; + isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad"); + isp_make_gone(isp, bus, tgt); } else { - isp_prt(isp, ISP_LOGCONFIG, prom, - lp->portid, lp->handle, - roles[lp->roles], - "changed and departed", - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed and departed", + (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } } else { lp->portid = lp->new_portid; lp->roles = lp->new_roles; - if (lp->ini_map_idx) { - int t = lp->ini_map_idx - 1; - FCPARAM(isp)->isp_ini_map[t] = - (lp - FCPARAM(isp)->portdb) + 1; - tgt = lp->ini_map_idx - 1; - isp_prt(isp, ISP_LOGCONFIG, prom2, - lp->portid, lp->handle, - roles[lp->roles], "changed at", tgt, - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + if (lp->dev_map_idx) { + int t = lp->dev_map_idx - 1; + FCPARAM(isp, bus)->isp_dev_map[t] = (lp - FCPARAM(isp, bus)->portdb) + 1; + tgt = lp->dev_map_idx - 1; + isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "changed at", tgt, + (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } else { - isp_prt(isp, ISP_LOGCONFIG, prom, - lp->portid, lp->handle, - roles[lp->roles], "changed", - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } } break; case ISPASYNC_DEV_STAYED: - lp = arg; - if (lp->ini_map_idx) { - tgt = lp->ini_map_idx - 1; - isp_prt(isp, ISP_LOGCONFIG, prom2, - lp->portid, lp->handle, - roles[lp->roles], "stayed at", tgt, - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + va_start(ap, cmd); + bus = va_arg(ap, int); + lp = va_arg(ap, fcportdb_t *); + va_end(ap); + if (lp->dev_map_idx) { + tgt = lp->dev_map_idx - 1; + isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "stayed at", tgt, + (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } else { - isp_prt(isp, ISP_LOGCONFIG, prom, - lp->portid, lp->handle, - roles[lp->roles], "stayed", - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "stayed", + (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } break; case ISPASYNC_DEV_GONE: - lp = arg; + va_start(ap, cmd); + bus = va_arg(ap, int); + lp = va_arg(ap, fcportdb_t *); + va_end(ap); /* * If this has a virtual target and we haven't marked it * that we're going to have isp_gdt tell the OS it's gone, @@ -3283,100 +4990,230 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) * If it isn't marked that isp_gdt is going to get rid of it, * announce that it's gone. */ - if (lp->ini_map_idx && lp->reserved == 0) { + if (lp->dev_map_idx && lp->reserved == 0) { lp->reserved = 1; - lp->new_reserved = isp->isp_osinfo.gone_device_time; + lp->new_reserved = ISP_FC_PC(isp, bus)->gone_device_time; lp->state = FC_PORTDB_STATE_ZOMBIE; - if (isp->isp_osinfo.gdt_running == 0) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "starting Gone Device Timer"); - isp->isp_osinfo.gdt_running = 1; - callout_reset(&isp->isp_osinfo.gdt, hz, - isp_gdt, isp); + if (ISP_FC_PC(isp, bus)->gdt_running == 0) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d starting Gone Device Timer", bus); + ISP_FC_PC(isp, bus)->gdt_running = 1; + callout_reset(&ISP_FC_PC(isp, bus)->gdt, hz, isp_gdt, ISP_FC_PC(isp, bus)); } - tgt = lp->ini_map_idx - 1; - isp_prt(isp, ISP_LOGCONFIG, prom2, - lp->portid, lp->handle, - roles[lp->roles], "gone zombie at", tgt, - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + tgt = lp->dev_map_idx - 1; + isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } else if (lp->reserved == 0) { - isp_prt(isp, ISP_LOGCONFIG, prom, - lp->portid, lp->handle, - roles[lp->roles], "departed", - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) lp->node_wwn, - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) lp->port_wwn); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "departed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); } break; case ISPASYNC_CHANGE_NOTIFY: { char *msg; - if (arg == ISPASYNC_CHANGE_PDB) { - msg = "Port Database Changed"; - } else if (arg == ISPASYNC_CHANGE_SNS) { - msg = "Name Server Database Changed"; + int evt, nphdl, nlstate, reason; + + va_start(ap, cmd); + bus = va_arg(ap, int); + evt = va_arg(ap, int); + if (IS_24XX(isp) && evt == ISPASYNC_CHANGE_PDB) { + nphdl = va_arg(ap, int); + nlstate = va_arg(ap, int); + reason = va_arg(ap, int); } else { - msg = "Other Change Notify"; + nphdl = NIL_HANDLE; + nlstate = reason = 0; } + va_end(ap); + + if (evt == ISPASYNC_CHANGE_PDB) { + msg = "Chan %d Port Database Changed"; + } else if (evt == ISPASYNC_CHANGE_SNS) { + msg = "Chan %d Name Server Database Changed"; + } else { + msg = "Chan %d Other Change Notify"; + } + /* * If the loop down timer is running, cancel it. */ - if (isp->isp_osinfo.ldt_running) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, - "Stopping Loop Down Timer"); - isp->isp_osinfo.ldt_running = 0; - callout_stop(&isp->isp_osinfo.ldt); + if (ISP_FC_PC(isp, bus)->ldt_running) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime); + ISP_FC_PC(isp, bus)->ldt_running = 0; + callout_stop(&ISP_FC_PC(isp, bus)->ldt); } - isp_prt(isp, ISP_LOGINFO, msg); - isp_freeze_loopdown(isp, msg); - wakeup(ISP_KT_WCHAN(isp)); + isp_prt(isp, ISP_LOGINFO, msg, bus); + if (ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) { + isp_freeze_loopdown(isp, bus, msg); + } + wakeup(ISP_FC_PC(isp, bus)); break; } #ifdef ISP_TARGET_MODE case ISPASYNC_TARGET_NOTIFY: { - tmd_notify_t *nt = arg; - isp_prt(isp, ISP_LOGALL, - "target notify code 0x%x", nt->nt_ncode); - break; - } - case ISPASYNC_TARGET_ACTION: - switch (((isphdr_t *)arg)->rqs_entry_type) { + isp_notify_t *notify; + va_start(ap, cmd); + notify = va_arg(ap, isp_notify_t *); + va_end(ap); + switch (notify->nt_ncode) { + case NT_ABORT_TASK: + case NT_ABORT_TASK_SET: + case NT_CLEAR_ACA: + case NT_CLEAR_TASK_SET: + case NT_LUN_RESET: + case NT_TARGET_RESET: + /* + * These are task management functions. + */ + isp_handle_platform_target_tmf(isp, notify); + break; + case NT_BUS_RESET: + case NT_LIP_RESET: + case NT_LINK_UP: + case NT_LINK_DOWN: + /* + * No action need be taken here. + */ + break; + case NT_HBA_RESET: + isp_del_all_wwn_entries(isp, ISP_NOCHAN); + break; + case NT_LOGOUT: + /* + * This is device arrival/departure notification + */ + isp_handle_platform_target_notify_ack(isp, notify); + break; + case NT_ARRIVED: + { + struct ac_contract ac; + struct ac_device_changed *fc; + + ac.contract_number = AC_CONTRACT_DEV_CHG; + fc = (struct ac_device_changed *) ac.contract_data; + fc->wwpn = notify->nt_wwn; + fc->port = notify->nt_sid; + fc->target = notify->nt_nphdl; + fc->arrived = 1; + xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac); + break; + } + case NT_DEPARTED: + { + struct ac_contract ac; + struct ac_device_changed *fc; + + ac.contract_number = AC_CONTRACT_DEV_CHG; + fc = (struct ac_device_changed *) ac.contract_data; + fc->wwpn = notify->nt_wwn; + fc->port = notify->nt_sid; + fc->target = notify->nt_nphdl; + fc->arrived = 0; + xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac); + break; + } default: - isp_prt(isp, ISP_LOGWARN, - "event 0x%x for unhandled target action", - ((isphdr_t *)arg)->rqs_entry_type); - break; - case RQSTYPE_NOTIFY: - if (IS_SCSI(isp)) { - rv = isp_handle_platform_notify_scsi(isp, - (in_entry_t *) arg); - } else { - rv = isp_handle_platform_notify_fc(isp, - (in_fcentry_t *) arg); - } - break; - case RQSTYPE_ATIO: - rv = isp_handle_platform_atio(isp, (at_entry_t *) arg); - break; - case RQSTYPE_ATIO2: - rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg); - break; - case RQSTYPE_CTIO3: - case RQSTYPE_CTIO2: - case RQSTYPE_CTIO: - rv = isp_handle_platform_ctio(isp, arg); - break; - case RQSTYPE_ENABLE_LUN: - case RQSTYPE_MODIFY_LUN: - isp_ledone(isp, (lun_entry_t *) arg); + isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode); + isp_handle_platform_target_notify_ack(isp, notify); break; } break; + } + case ISPASYNC_TARGET_ACTION: + { + isphdr_t *hp; + + va_start(ap, cmd); + hp = va_arg(ap, isphdr_t *); + va_end(ap); + switch (hp->rqs_entry_type) { + default: + isp_prt(isp, ISP_LOGWARN, "%s: unhandled target action 0x%x", __func__, hp->rqs_entry_type); + break; + case RQSTYPE_NOTIFY: + if (IS_SCSI(isp)) { + isp_handle_platform_notify_scsi(isp, (in_entry_t *) hp); + } else if (IS_24XX(isp)) { + isp_handle_platform_notify_24xx(isp, (in_fcentry_24xx_t *) hp); + } else { + isp_handle_platform_notify_fc(isp, (in_fcentry_t *) hp); + } + break; + case RQSTYPE_ATIO: + if (IS_24XX(isp)) { + isp_handle_platform_atio7(isp, (at7_entry_t *) hp); + } else { + isp_handle_platform_atio(isp, (at_entry_t *) hp); + } + break; + case RQSTYPE_ATIO2: + isp_handle_platform_atio2(isp, (at2_entry_t *) hp); + break; + case RQSTYPE_CTIO7: + case RQSTYPE_CTIO3: + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO: + isp_handle_platform_ctio(isp, hp); + break; + case RQSTYPE_ABTS_RCVD: + { + abts_t *abts = (abts_t *)hp; + isp_notify_t notify, *nt = ¬ify; + tstate_t *tptr; + fcportdb_t *lp; + uint16_t chan; + uint32_t sid, did; + + did = (abts->abts_did_hi << 16) | abts->abts_did_lo; + sid = (abts->abts_sid_hi << 16) | abts->abts_sid_lo; + ISP_MEMZERO(nt, sizeof (isp_notify_t)); + + nt->nt_hba = isp; + nt->nt_did = did; + nt->nt_nphdl = abts->abts_nphdl; + nt->nt_sid = sid; + isp_find_chan_by_did(isp, did, &chan); + if (chan == ISP_NOCHAN) { + nt->nt_tgt = TGT_ANY; + } else { + nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn; + if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) { + nt->nt_wwn = lp->port_wwn; + } else { + nt->nt_wwn = INI_ANY; + } + } + /* + * Try hard to find the lun for this command. + */ + tptr = get_lun_statep_from_tag(isp, chan, abts->abts_rxid_task); + if (tptr) { + nt->nt_lun = xpt_path_lun_id(tptr->owner); + rls_lun_statep(isp, tptr); + } else { + nt->nt_lun = LUN_ANY; + } + nt->nt_need_ack = 1; + nt->nt_tagval = abts->abts_rxid_task; + nt->nt_tagval |= (((uint64_t) abts->abts_rxid_abts) << 32); + if (abts->abts_rxid_task == ISP24XX_NO_TASK) { + isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x has no task id (rx_id 0x%04x ox_id 0x%04x)", + abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rx_id, abts->abts_ox_id); + } else { + isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x for task 0x%x (rx_id 0x%04x ox_id 0x%04x)", + abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rxid_task, abts->abts_rx_id, abts->abts_ox_id); + } + nt->nt_channel = chan; + nt->nt_ncode = NT_ABORT_TASK; + nt->nt_lreserved = hp; + isp_handle_platform_target_tmf(isp, nt); + break; + } + case RQSTYPE_ENABLE_LUN: + case RQSTYPE_MODIFY_LUN: + isp_ledone(isp, (lun_entry_t *) hp); + break; + } + break; + } #endif case ISPASYNC_FW_CRASH: { @@ -3387,36 +5224,18 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg) } else { mbox6 = 0; } - isp_prt(isp, ISP_LOGERR, - "Internal Firmware Error on bus %d @ RISC Address 0x%x", - mbox6, mbox1); -#ifdef ISP_FW_CRASH_DUMP + isp_prt(isp, ISP_LOGERR, "Internal Firmware Error on bus %d @ RISC Address 0x%x", mbox6, mbox1); mbox1 = isp->isp_osinfo.mbox_sleep_ok; isp->isp_osinfo.mbox_sleep_ok = 0; - if (IS_FC(isp)) { - FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; - FCPARAM(isp)->isp_loopstate = LOOP_NIL; - isp_freeze_loopdown(isp, "f/w crash"); - isp_fw_dump(isp); - } - isp_reinit(isp); + isp_reinit(isp, 1); isp->isp_osinfo.mbox_sleep_ok = mbox1; -#else - mbox1 = isp->isp_osinfo.mbox_sleep_ok; - isp->isp_osinfo.mbox_sleep_ok = 0; - isp_reinit(isp); - isp->isp_osinfo.mbox_sleep_ok = mbox1; -#endif isp_async(isp, ISPASYNC_FW_RESTARTED, NULL); break; } - case ISPASYNC_UNHANDLED_RESPONSE: - break; default: isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd); break; } - return (rv); } @@ -3434,6 +5253,94 @@ isp_uninit(ispsoftc_t *isp) ISP_DISABLE_INTS(isp); } +/* + * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them + * up from our platform default (defww{p|n}n) and morph them based upon + * channel. + * + * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them + * based upon channel. + */ + +uint64_t +isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn) +{ + uint64_t seed; + struct isp_fc *fc = ISP_FC_PC(isp, chan); + + /* + * If we're asking for a active WWN, the default overrides get + * returned, otherwise the NVRAM value is picked. + * + * If we're asking for a default WWN, we just pick the default override. + */ + if (isactive) { + seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; + if (seed) { + return (seed); + } + seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram; + } else { + seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; + } + + + /* + * For channel zero just return what we have. For either ACIIVE or + * DEFAULT cases, we depend on default override of NVRAM values for + * channel zero. + */ + if (chan == 0) { + return (seed); + } + + /* + * For other channels, we are doing one of three things: + * + * 1. If what we have now is non-zero, return it. Otherwise we morph + * values from channel 0. 2. If we're here for a WWPN we synthesize + * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a + * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA. + */ + + if (seed) { + return (seed); + } + if (isactive) { + seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram; + } else { + seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn; + } + + if (((seed >> 60) & 0xf) == 2) { + /* + * The type 2 NAA fields for QLogic cards appear be laid out + * thusly: + * + * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56 + * port (1) or node (0) WWN distinguishor bit 48 + * physical port on dual-port chips (23XX/24XX) + * + * This is somewhat nutty, particularly since bit 48 is + * irrelevant as they assign seperate serial numbers to + * different physical ports anyway. + * + * We'll stick our channel number plus one first into bits + * 57..59 and thence into bits 52..55 which allows for 8 bits + * of channel which is comfortably more than our maximum + * (126) now. + */ + seed &= ~0x0FF0000000000000ULL; + if (iswwnn == 0) { + seed |= ((uint64_t) (chan + 1) & 0xf) << 56; + seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52; + } + } else { + seed = 0; + } + return (seed); +} + void isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) { @@ -3489,13 +5396,7 @@ isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp) isp->isp_osinfo.mbox_sleep_ok = 0; isp->isp_osinfo.mbox_sleeping = 1; for (olim = 0; olim < max; olim++) { -#if __FreeBSD_version < 700037 - tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep", - isp_mstohz(ms)); -#else - msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, - PRIBIO, "ispmbx_sleep", isp_mstohz(ms)); -#endif + msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, PRIBIO, "ispmbx_sleep", isp_mstohz(ms)); if (isp->isp_osinfo.mboxcmd_done) { break; } @@ -3516,7 +5417,7 @@ isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp) break; } } - USEC_DELAY(100); + ISP_DELAY(100); } if (isp->isp_osinfo.mboxcmd_done) { break; @@ -3524,10 +5425,8 @@ isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp) } } if (isp->isp_osinfo.mboxcmd_done == 0) { - isp_prt(isp, ISP_LOGWARN, - "%s Mailbox Command (0x%x) Timeout (%uus)", - isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", - isp->isp_lastmbxcmd, usecs); + isp_prt(isp, ISP_LOGWARN, "%s Mailbox Command (0x%x) Timeout (%uus) (started @ %s:%d)", + isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", isp->isp_lastmbxcmd, usecs, mbp->func, mbp->lineno); mbp->param[0] = MBOX_TIMEOUT; isp->isp_osinfo.mboxcmd_done = 1; } @@ -3548,6 +5447,18 @@ isp_mbox_release(ispsoftc_t *isp) isp->isp_osinfo.mboxbsy = 0; } +int +isp_fc_scratch_acquire(ispsoftc_t *isp, int chan) +{ + int ret = 0; + if (isp->isp_osinfo.pc.fc[chan].fcbsy) { + ret = -1; + } else { + isp->isp_osinfo.pc.fc[chan].fcbsy = 1; + } + return (ret); +} + int isp_mstohz(int ms) { @@ -3586,11 +5497,19 @@ void isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD); } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE); } bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); } + +void +isp_timer(void *arg) +{ + ispsoftc_t *isp = arg; +#ifdef ISP_TARGET_MODE + isp_tmcmd_restart(isp); +#endif + callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp); +} diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index e8c36ca7a974..2988e3095eec 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -2,7 +2,7 @@ /*- * Qlogic ISP SCSI Host Adapter FreeBSD Wrapper Definitions * - * Copyright (c) 1997-2006 by Matthew Jacob + * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,27 +32,19 @@ #include #include #include -#if __FreeBSD_version < 500000 -#include -#include -#include -#else #include #include #include #include #include #include -#endif #include #include #include -#if __FreeBSD_version < 500000 -#include -#endif #include +#include #include #include @@ -67,13 +59,8 @@ #include "opt_ddb.h" #include "opt_isp.h" -#if __FreeBSD_version < 500000 -#define ISP_PLATFORM_VERSION_MAJOR 4 -#define ISP_PLATFORM_VERSION_MINOR 17 -#else -#define ISP_PLATFORM_VERSION_MAJOR 5 -#define ISP_PLATFORM_VERSION_MINOR 9 -#endif +#define ISP_PLATFORM_VERSION_MAJOR 7 +#define ISP_PLATFORM_VERSION_MINOR 0 /* * Efficiency- get rid of SBus code && tests unless we need them. @@ -84,28 +71,30 @@ #define ISP_SBUS_SUPPORTED 0 #endif - -#if __FreeBSD_version < 500000 -#define ISP_IFLAGS INTR_TYPE_CAM -#elif __FreeBSD_version < 700037 -#define ISP_IFLAGS INTR_TYPE_CAM | INTR_ENTROPY -#else #define ISP_IFLAGS INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE -#endif - -#if __FreeBSD_version < 700000 -typedef void ispfwfunc(int, int, int, const void **); -#endif #ifdef ISP_TARGET_MODE #define ISP_TARGET_FUNCTIONS 1 -#define ATPDPSIZE 256 +#define ATPDPSIZE 4096 + +#include + typedef struct { + void * next; uint32_t orig_datalen; uint32_t bytes_xfered; uint32_t last_xframt; - uint32_t tag : 16, - lun : 13, /* not enough */ + uint32_t tag; + uint32_t lun; + uint32_t nphdl; + uint32_t sid; + uint32_t portid; + uint32_t + oxid : 16, + cdb0 : 8, + : 1, + dead : 1, + tattr : 3, state : 3; } atio_private_data_t; #define ATPD_STATE_FREE 0 @@ -115,23 +104,34 @@ typedef struct { #define ATPD_STATE_LAST_CTIO 4 #define ATPD_STATE_PDON 5 +typedef union inot_private_data inot_private_data_t; +union inot_private_data { + inot_private_data_t *next; + struct { + isp_notify_t nt; /* must be first! */ + uint8_t data[64]; /* sb QENTRY_LEN, but order of definitions is wrong */ + uint32_t tag_id, seq_id; + } rd; +}; + typedef struct tstate { - struct tstate *next; + SLIST_ENTRY(tstate) next; struct cam_path *owner; struct ccb_hdr_slist atios; struct ccb_hdr_slist inots; - lun_id_t lun; - int bus; uint32_t hold; int atio_count; int inot_count; + inot_private_data_t * restart_queue; + inot_private_data_t * ntfree; + inot_private_data_t ntpool[ATPDPSIZE]; + atio_private_data_t * atfree; + atio_private_data_t atpool[ATPDPSIZE]; } tstate_t; -#define LUN_HASH_SIZE 32 -#define LUN_HASH_FUNC(isp, port, lun) \ - ((IS_DUALBUS(isp)) ? \ - (((lun) & ((LUN_HASH_SIZE >> 1) - 1)) << (port)) : \ - ((lun) & (LUN_HASH_SIZE - 1))) +#define LUN_HASH_SIZE 32 +#define LUN_HASH_FUNC(lun) ((lun) & (LUN_HASH_SIZE - 1)) + #endif /* @@ -146,72 +146,162 @@ struct isp_pcmd { #define ISP_PCMD(ccb) (ccb)->ccb_h.spriv_ptr1 #define PISP_PCMD(ccb) ((struct isp_pcmd *)ISP_PCMD(ccb)) -struct isposinfo { - struct ispsoftc * next; - bus_space_tag_t bus_tag; - bus_space_handle_t bus_handle; - bus_dma_tag_t dmat; - uint64_t default_port_wwn; - uint64_t default_node_wwn; - uint32_t default_id; - device_t dev; - struct cam_sim *sim; - struct cam_path *path; - struct cam_sim *sim2; - struct cam_path *path2; - struct intr_config_hook ehook; - uint32_t loop_down_time; - uint32_t loop_down_limit; - uint32_t gone_device_time; - uint32_t : 5, +/* + * Per channel information + */ +SLIST_HEAD(tslist, tstate); + +struct isp_fc { + struct cam_sim *sim; + struct cam_path *path; + struct ispsoftc *isp; + struct proc *kproc; + bus_dma_tag_t tdmat; + bus_dmamap_t tdmap; + uint64_t def_wwpn; + uint64_t def_wwnn; + uint32_t loop_down_time; + uint32_t loop_down_limit; + uint32_t gone_device_time; + uint32_t +#ifdef ISP_TARGET_MODE +#ifdef ISP_INTERNAL_TARGET + proc_active : 1, +#endif + tm_luns_enabled : 1, + tm_enable_defer : 1, + tm_enabled : 1, +#endif simqfrozen : 3, + default_id : 8, hysteresis : 8, + role : 2, gdt_running : 1, ldt_running : 1, - disabled : 1, - fcbsy : 1, - mbox_sleeping : 1, - mbox_sleep_ok : 1, - mboxcmd_done : 1, - mboxbsy : 1; - struct callout ldt; /* loop down timer */ - struct callout gdt; /* gone device timer */ -#if __FreeBSD_version < 500000 - uint32_t splcount; - uint32_t splsaved; -#else - struct mtx lock; - const struct firmware * fw; - union { - struct { - char wwnn[19]; - char wwpn[19]; - } fc; - } sysctl_info; + loop_dead : 1, + fcbsy : 1; + struct callout ldt; /* loop down timer */ + struct callout gdt; /* gone device timer */ +#ifdef ISP_TARGET_MODE + struct tslist lun_hash[LUN_HASH_SIZE]; +#ifdef ISP_INTERNAL_TARGET + struct proc * target_proc; #endif - struct proc *kproc; +#endif +}; + +struct isp_spi { + struct cam_sim *sim; + struct cam_path *path; + uint32_t +#ifdef ISP_TARGET_MODE +#ifdef ISP_INTERNAL_TARGET + proc_active : 1, +#endif + tm_luns_enabled : 1, + tm_enable_defer : 1, + tm_enabled : 1, +#endif + simqfrozen : 3, + role : 3, + iid : 4; +#ifdef ISP_TARGET_MODE + struct tslist lun_hash[LUN_HASH_SIZE]; +#ifdef ISP_INTERNAL_TARGET + struct proc * target_proc; +#endif +#endif +}; + +struct isposinfo { + /* + * Linkage, locking, and identity + */ + struct mtx lock; + device_t dev; + struct cdev * cdev; + struct intr_config_hook ehook; + struct cam_devq * devq; + + /* + * Firmware pointer + */ + const struct firmware * fw; + + /* + * DMA related sdtuff + */ + bus_space_tag_t bus_tag; + bus_dma_tag_t dmat; + bus_space_handle_t bus_handle; bus_dma_tag_t cdmat; bus_dmamap_t cdmap; -#define isp_cdmat isp_osinfo.cdmat -#define isp_cdmap isp_osinfo.cdmap + /* - * Per command information. + * Command and transaction related related stuff */ struct isp_pcmd * pcmd_pool; struct isp_pcmd * pcmd_free; + uint32_t #ifdef ISP_TARGET_MODE -#define TM_WILDCARD_ENABLED 0x02 -#define TM_TMODE_ENABLED 0x01 - uint8_t tmflags[2]; /* two busses */ -#define NLEACT 4 - union ccb * leact[NLEACT]; - tstate_t tsdflt[2]; /* two busses */ - tstate_t *lun_hash[LUN_HASH_SIZE]; - atio_private_data_t atpdp[ATPDPSIZE]; + tmwanted : 1, + tmbusy : 1, +#else + : 2, #endif + forcemulti : 1, + timer_active : 1, + autoconf : 1, + ehook_active : 1, + disabled : 1, + mbox_sleeping : 1, + mbox_sleep_ok : 1, + mboxcmd_done : 1, + mboxbsy : 1; + + struct callout tmo; /* general timer */ + + /* + * misc- needs to be sorted better XXXXXX + */ + int framesize; + int exec_throttle; + int cont_max; + +#ifdef ISP_TARGET_MODE + cam_status * rptr; +#endif + + /* + * Per-type private storage... + */ + union { + struct isp_fc *fc; + struct isp_spi *spi; + void *ptr; + } pc; }; -#define ISP_KT_WCHAN(isp) (&(isp)->isp_osinfo.kproc) +#define ISP_FC_PC(isp, chan) (&(isp)->isp_osinfo.pc.fc[(chan)]) +#define ISP_SPI_PC(isp, chan) (&(isp)->isp_osinfo.pc.spi[(chan)]) +#define ISP_GET_PC(isp, chan, tag, rslt) \ + if (IS_SCSI(isp)) { \ + rslt = ISP_SPI_PC(isp, chan)-> tag; \ + } else { \ + rslt = ISP_FC_PC(isp, chan)-> tag; \ + } +#define ISP_GET_PC_ADDR(isp, chan, tag, rp) \ + if (IS_SCSI(isp)) { \ + rp = &ISP_SPI_PC(isp, chan)-> tag; \ + } else { \ + rp = &ISP_FC_PC(isp, chan)-> tag; \ + } +#define ISP_SET_PC(isp, chan, tag, val) \ + if (IS_SCSI(isp)) { \ + ISP_SPI_PC(isp, chan)-> tag = val; \ + } else { \ + ISP_FC_PC(isp, chan)-> tag = val; \ + } #define isp_lock isp_osinfo.lock #define isp_bus_tag isp_osinfo.bus_tag @@ -220,37 +310,26 @@ struct isposinfo { /* * Locking macros... */ -#if __FreeBSD_version < 500000 -#define ISP_LOCK(isp) \ - if (isp->isp_osinfo.splcount++ == 0) { \ - isp->isp_osinfo.splsaved = splcam(); \ - } -#define ISP_UNLOCK(isp) \ - if (isp->isp_osinfo.splcount > 1) { \ - isp->isp_osinfo.splcount--; \ - } else { \ - isp->isp_osinfo.splcount = 0; \ - splx(isp->isp_osinfo.splsaved); \ - } -#elif __FreeBSD_version < 700037 -#define ISP_LOCK(isp) do {} while (0) -#define ISP_UNLOCK(isp) do {} while (0) -#else #define ISP_LOCK(isp) mtx_lock(&isp->isp_osinfo.lock) #define ISP_UNLOCK(isp) mtx_unlock(&isp->isp_osinfo.lock) -#endif /* * Required Macros/Defines */ -#define ISP2100_SCRLEN 0x1000 +#define ISP_FC_SCRLEN 0x1000 -#define MEMZERO(a, b) memset(a, 0, b) -#define MEMCPY memcpy -#define SNPRINTF snprintf -#define USEC_DELAY DELAY -#define USEC_SLEEP(isp, x) DELAY(x) +#define ISP_MEMZERO(a, b) memset(a, 0, b) +#define ISP_MEMCPY memcpy +#define ISP_SNPRINTF snprintf +#define ISP_DELAY DELAY +#define ISP_SLEEP(isp, x) DELAY(x) + +#ifndef DIAGNOSTIC +#define ISP_INLINE __inline +#else +#define ISP_INLINE +#endif #define NANOTIME_T struct timespec #define GET_NANOTIME nanotime @@ -263,17 +342,19 @@ struct isposinfo { switch (type) { \ case SYNC_SFORDEV: \ case SYNC_REQUEST: \ - bus_dmamap_sync(isp->isp_cdmat, isp->isp_cdmap, \ + bus_dmamap_sync(isp->isp_osinfo.cdmat, \ + isp->isp_osinfo.cdmap, \ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \ break; \ case SYNC_SFORCPU: \ case SYNC_RESULT: \ - bus_dmamap_sync(isp->isp_cdmat, isp->isp_cdmap, \ + bus_dmamap_sync(isp->isp_osinfo.cdmat, \ + isp->isp_osinfo.cdmap, \ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \ break; \ case SYNC_REG: \ - bus_space_barrier(isp->isp_bus_tag, \ - isp->isp_bus_handle, offset, size, \ + bus_space_barrier(isp->isp_osinfo.bus_tag, \ + isp->isp_osinfo.bus_handle, offset, size, \ BUS_SPACE_BARRIER_READ); \ break; \ default: \ @@ -285,13 +366,8 @@ default: \ #define MBOX_NOTIFY_COMPLETE isp_mbox_notify_done #define MBOX_RELEASE isp_mbox_release -#define FC_SCRATCH_ACQUIRE(isp) \ - if (isp->isp_osinfo.fcbsy) { \ - isp_prt(isp, ISP_LOGWARN, \ - "FC scratch area busy (line %d)!", __LINE__); \ - } else \ - isp->isp_osinfo.fcbsy = 1 -#define FC_SCRATCH_RELEASE(isp) isp->isp_osinfo.fcbsy = 0 +#define FC_SCRATCH_ACQUIRE isp_fc_scratch_acquire +#define FC_SCRATCH_RELEASE(isp, chan) isp->isp_osinfo.pc.fc[chan].fcbsy = 0 #ifndef SCSI_GOOD #define SCSI_GOOD SCSI_STATUS_OK @@ -308,6 +384,25 @@ default: \ #define XS_T struct ccb_scsiio #define XS_DMA_ADDR_T bus_addr_t +#define XS_GET_DMA64_SEG(a, b, c) \ +{ \ + ispds64_t *d = a; \ + bus_dma_segment_t *e = b; \ + uint32_t f = c; \ + e += f; \ + d->ds_base = DMA_LO32(e->ds_addr); \ + d->ds_basehi = DMA_HI32(e->ds_addr); \ + d->ds_count = e->ds_len; \ +} +#define XS_GET_DMA_SEG(a, b, c) \ +{ \ + ispds_t *d = a; \ + bus_dma_segment_t *e = b; \ + uint32_t f = c; \ + e += f; \ + d->ds_base = DMA_LO32(e->ds_addr); \ + d->ds_count = e->ds_len; \ +} #define XS_ISP(ccb) cam_sim_softc(xpt_path_sim((ccb)->ccb_h.path)) #define XS_CHANNEL(ccb) cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path)) #define XS_TGT(ccb) (ccb)->ccb_h.target_id @@ -320,7 +415,8 @@ default: \ #define XS_CDBLEN(ccb) (ccb)->cdb_len #define XS_XFRLEN(ccb) (ccb)->dxfer_len #define XS_TIME(ccb) (ccb)->ccb_h.timeout -#define XS_RESID(ccb) (ccb)->resid +#define XS_GET_RESID(ccb) (ccb)->resid +#define XS_SET_RESID(ccb, r) (ccb)->resid = r #define XS_STSP(ccb) (&(ccb)->scsi_status) #define XS_SNSP(ccb) (&(ccb)->sense_data) @@ -367,23 +463,27 @@ default: \ #define XS_SET_STATE_STAT(a, b, c) -#define DEFAULT_IID(x) (isp)->isp_osinfo.default_id -#define DEFAULT_LOOPID(x) (isp)->isp_osinfo.default_id -#define DEFAULT_NODEWWN(isp) (isp)->isp_osinfo.default_node_wwn -#define DEFAULT_PORTWWN(isp) (isp)->isp_osinfo.default_port_wwn -#define ISP_NODEWWN(isp) FCPARAM(isp)->isp_wwnn_nvram -#define ISP_PORTWWN(isp) FCPARAM(isp)->isp_wwpn_nvram +#define DEFAULT_FRAMESIZE(isp) isp->isp_osinfo.framesize +#define DEFAULT_EXEC_THROTTLE(isp) isp->isp_osinfo.exec_throttle +#define GET_DEFAULT_ROLE(isp, chan) \ + (IS_FC(isp)? ISP_FC_PC(isp, chan)->role : ISP_SPI_PC(isp, chan)->role) +#define SET_DEFAULT_ROLE(isp, chan, val) \ + if (IS_FC(isp)) { \ + ISP_FC_PC(isp, chan)->role = val; \ + } else { \ + ISP_SPI_PC(isp, chan)->role = val; \ + } + +#define DEFAULT_IID(isp, chan) isp->isp_osinfo.pc.spi[chan].iid + +#define DEFAULT_LOOPID(x, chan) isp->isp_osinfo.pc.fc[chan].default_id + +#define DEFAULT_NODEWWN(isp, chan) isp_default_wwn(isp, chan, 0, 1) +#define DEFAULT_PORTWWN(isp, chan) isp_default_wwn(isp, chan, 0, 0) +#define ACTIVE_NODEWWN(isp, chan) isp_default_wwn(isp, chan, 1, 1) +#define ACTIVE_PORTWWN(isp, chan) isp_default_wwn(isp, chan, 1, 0) -#if __FreeBSD_version < 500000 -#if _BYTE_ORDER == _LITTLE_ENDIAN -#define bswap16 htobe16 -#define bswap32 htobe32 -#else -#define bswap16 htole16 -#define bswap32 htole32 -#endif -#endif #if BYTE_ORDER == BIG_ENDIAN #ifdef ISP_SBUS_SUPPORTED @@ -450,10 +550,6 @@ default: \ #include #include -#ifdef ISP_TARGET_MODE -#include -#endif - /* * isp_osinfo definiitions && shorthand */ @@ -461,17 +557,15 @@ default: \ #define SIMQFRZ_LOOPDOWN 0x2 #define SIMQFRZ_TIMED 0x4 -#define isp_sim isp_osinfo.sim -#define isp_path isp_osinfo.path -#define isp_sim2 isp_osinfo.sim2 -#define isp_path2 isp_osinfo.path2 #define isp_dev isp_osinfo.dev /* * prototypes for isp_pci && isp_freebsd to share */ -extern void isp_attach(ispsoftc_t *); +extern int isp_attach(ispsoftc_t *); +extern void isp_detach(ispsoftc_t *); extern void isp_uninit(ispsoftc_t *); +extern uint64_t isp_default_wwn(ispsoftc_t *, int, int, int); /* * driver global data @@ -481,23 +575,14 @@ extern int isp_fabric_hysteresis; extern int isp_loop_down_limit; extern int isp_gone_device_time; extern int isp_quickboot_time; +extern int isp_autoconfig; /* * Platform private flags */ #define ISP_SPRIV_ERRSET 0x1 -#define ISP_SPRIV_INWDOG 0x2 -#define ISP_SPRIV_GRACE 0x4 #define ISP_SPRIV_DONE 0x8 -#define XS_CMD_S_WDOG(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_INWDOG -#define XS_CMD_C_WDOG(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_INWDOG -#define XS_CMD_WDOG_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_INWDOG) - -#define XS_CMD_S_GRACE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_GRACE -#define XS_CMD_C_GRACE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_GRACE -#define XS_CMD_GRACE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_GRACE) - #define XS_CMD_S_DONE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_DONE #define XS_CMD_C_DONE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_DONE #define XS_CMD_DONE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_DONE) @@ -513,6 +598,7 @@ int isp_mbox_acquire(ispsoftc_t *); void isp_mbox_wait_complete(ispsoftc_t *, mbreg_t *); void isp_mbox_notify_done(ispsoftc_t *); void isp_mbox_release(ispsoftc_t *); +int isp_fc_scratch_acquire(ispsoftc_t *, int); int isp_mstohz(int); void isp_platform_intr(void *); void isp_common_dmateardown(ispsoftc_t *, struct ccb_scsiio *, uint32_t); @@ -520,75 +606,27 @@ void isp_common_dmateardown(ispsoftc_t *, struct ccb_scsiio *, uint32_t); /* * Platform Version specific defines */ -#if __FreeBSD_version < 500000 -#define BUS_DMA_ROOTARG(x) NULL -#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \ - bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) -#elif __FreeBSD_version < 700020 -#define BUS_DMA_ROOTARG(x) NULL -#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \ - bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \ - busdma_lock_mutex, &Giant, z) -#elif __FreeBSD_version < 700037 -#define BUS_DMA_ROOTARG(x) bus_get_dma_tag(x) -#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \ - bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \ - busdma_lock_mutex, &Giant, z) -#else #define BUS_DMA_ROOTARG(x) bus_get_dma_tag(x) #define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \ bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \ busdma_lock_mutex, &isp->isp_osinfo.lock, z) -#endif -#if __FreeBSD_version < 700031 -#define isp_setup_intr(d, i, f, U, if, ifa, hp) \ - bus_setup_intr(d, i, f, if, ifa, hp) -#else #define isp_setup_intr bus_setup_intr -#endif -#if __FreeBSD_version < 500000 -#define isp_sim_alloc cam_sim_alloc -#define isp_callout_init(x) callout_init(x) -#elif __FreeBSD_version < 700037 -#define isp_callout_init(x) callout_init(x, 0) -#define isp_sim_alloc cam_sim_alloc -#else -#define isp_callout_init(x) callout_init(x, 1) #define isp_sim_alloc(a, b, c, d, e, f, g, h) \ cam_sim_alloc(a, b, c, d, e, &(d)->isp_osinfo.lock, f, g, h) -#endif /* Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE */ -#define ISP_MAXPHYS (128 * 1024) -#define ISP_NSEGS ((ISP_MAXPHYS / PAGE_SIZE) + 1) +#define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1) + +#define ISP_PATH_PRT(i, l, p, ...) \ + if ((l) == ISP_LOGALL || ((l)& (i)->isp_dblev) != 0) { \ + xpt_print(p, __VA_ARGS__); \ + } /* * Platform specific inline functions */ -static __inline int isp_get_pcmd(ispsoftc_t *, union ccb *); -static __inline void isp_free_pcmd(ispsoftc_t *, union ccb *); - -static __inline int -isp_get_pcmd(ispsoftc_t *isp, union ccb *ccb) -{ - ISP_PCMD(ccb) = isp->isp_osinfo.pcmd_free; - if (ISP_PCMD(ccb) == NULL) { - return (-1); - } - isp->isp_osinfo.pcmd_free = ((struct isp_pcmd *)ISP_PCMD(ccb))->next; - return (0); -} - -static __inline void -isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb) -{ - ((struct isp_pcmd *)ISP_PCMD(ccb))->next = isp->isp_osinfo.pcmd_free; - isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb); - ISP_PCMD(ccb) = NULL; -} - /* * ISP General Library functions diff --git a/sys/dev/isp/isp_ioctl.h b/sys/dev/isp/isp_ioctl.h index b52c6f196285..8fda052067bb 100644 --- a/sys/dev/isp/isp_ioctl.h +++ b/sys/dev/isp/isp_ioctl.h @@ -54,6 +54,8 @@ * This ioctl performs a reset and then will set the adapter to the * role that was passed in (the old role will be returned). It almost * goes w/o saying: use with caution. + * + * Channel selector stored in bits 8..32 as input to driver. */ #define ISP_SETROLE _IOWR(ISP_IOC, 4, int) @@ -64,6 +66,7 @@ /* * Get the current adapter role + * Channel selector passed in first argument. */ #define ISP_GETROLE _IOR(ISP_IOC, 5, int) @@ -107,8 +110,9 @@ typedef struct { * only), 24 bit Port ID and Node and Port WWNs. */ struct isp_fc_device { - uint32_t loopid; /* 0..255 */ - uint32_t : 6, + uint32_t loopid; /* 0..255,2047 */ + uint32_t + chan : 6, role : 2, portid : 24; /* 24 bit Port ID */ uint64_t node_wwn; @@ -129,18 +133,16 @@ struct isp_fc_device { struct isp_hba_device { uint32_t : 8, - : 4, fc_speed : 4, /* Gbps */ - : 2, - fc_class2 : 1, - fc_ip_supported : 1, - fc_scsi_supported : 1, + : 1, fc_topology : 3, - fc_loopid : 8; + fc_channel : 8, + fc_loopid : 16; uint8_t fc_fw_major; uint8_t fc_fw_minor; uint8_t fc_fw_micro; - uint8_t reserved; + uint8_t fc_nchannels; /* number of supported channels */ + uint16_t fc_nports; /* number of supported ports */ uint64_t nvram_node_wwn; uint64_t nvram_port_wwn; uint64_t active_node_wwn; @@ -153,14 +155,16 @@ struct isp_hba_device { #define ISP_TOPO_NPORT 3 /* N-port */ #define ISP_TOPO_FPORT 4 /* F-port */ -#define ISP_FC_GETHINFO _IOR(ISP_IOC, 12, struct isp_hba_device) +/* don't use 12 any more */ +#define ISP_FC_GETHINFO _IOWR(ISP_IOC, 13, struct isp_hba_device) /* * Various Reset Goodies */ struct isp_fc_tsk_mgmt { - uint32_t loopid; /* 0..255 */ - uint32_t lun; + uint32_t loopid; /* 0..255/2048 */ + uint16_t lun; + uint16_t chan; enum { IPT_CLEAR_ACA, IPT_TARGET_RESET, @@ -169,4 +173,18 @@ struct isp_fc_tsk_mgmt { IPT_ABORT_TASK_SET } action; }; -#define ISP_TSK_MGMT _IOWR(ISP_IOC, 97, struct isp_fc_tsk_mgmt) +/* don't use 97 any more */ +#define ISP_TSK_MGMT _IOWR(ISP_IOC, 98, struct isp_fc_tsk_mgmt) + +/* + * Just gimme a list of WWPNs that are logged into us. + */ +typedef struct { + uint16_t count; + uint16_t channel; + struct wwnpair { + uint64_t wwnn; + uint64_t wwpn; + } wwns[1]; +} isp_dlist_t; +#define ISP_FC_GETDLIST _IO(ISP_IOC, 14) diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index 1d6e6ee8b277..5e6430905bfe 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -1,17 +1,17 @@ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -23,6 +23,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Qlogic Host Adapter Internal Library Functions @@ -47,6 +48,203 @@ __FBSDID("$FreeBSD$"); #include "isp_solaris.h" #endif +const char *isp_class3_roles[4] = { + "None", "Target", "Initiator", "Target/Initiator" +}; + +/* + * Command shipping- finish off first queue entry and do dma mapping and additional segments as needed. + * + * Called with the first queue entry at least partially filled out. + */ +int +isp_send_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir) +{ + uint8_t storage[QENTRY_LEN]; + uint8_t type, nqe; + uint32_t seg, curseg, seglim, nxt, nxtnxt, ddf; + ispds_t *dsp = NULL; + ispds64_t *dsp64 = NULL; + void *qe0, *qe1; + + qe0 = isp_getrqentry(isp); + if (qe0 == NULL) { + return (CMD_EAGAIN); + } + nxt = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); + + type = ((isphdr_t *)fqe)->rqs_entry_type; + nqe = 1; + + /* + * If we have no data to transmit, just copy the first IOCB and start it up. + */ + if (ddir == ISP_NOXFR) { + if (type == RQSTYPE_T2RQS || type == RQSTYPE_T3RQS) { + ddf = CT2_NO_DATA; + } else { + ddf = 0; + } + goto copy_and_sync; + } + + /* + * First figure out how many pieces of data to transfer and what kind and how many we can put into the first queue entry. + */ + switch (type) { + case RQSTYPE_REQUEST: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp = ((ispreq_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG; + break; + case RQSTYPE_CMDONLY: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + seglim = 0; + break; + case RQSTYPE_T2RQS: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp = ((ispreqt2_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T2; + break; + case RQSTYPE_A64: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp64 = ((ispreqt3_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T3; + break; + case RQSTYPE_T3RQS: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp64 = ((ispreqt3_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T3; + break; + case RQSTYPE_T7RQS: + ddf = (ddir == ISP_TO_DEVICE)? FCP_CMND_DATA_WRITE : FCP_CMND_DATA_READ; + dsp64 = &((ispreqt7_t *)fqe)->req_dataseg; + seglim = 1; + break; + default: + return (CMD_COMPLETE); + } + + if (seglim > nsegs) { + seglim = nsegs; + } + + for (seg = curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + + + /* + * Second, start building additional continuation segments as needed. + */ + while (seg < nsegs) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + ISP_MEMZERO(storage, QENTRY_LEN); + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (dsp64) { + ispcontreq64_t *crq = (ispcontreq64_t *) storage; + seglim = ISP_CDSEG64; + crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; + crq->req_header.rqs_entry_count = 1; + dsp64 = crq->req_dataseg; + } else { + ispcontreq_t *crq = (ispcontreq_t *) storage; + seglim = ISP_CDSEG; + crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; + crq->req_header.rqs_entry_count = 1; + dsp = crq->req_dataseg; + } + if (seg + seglim > nsegs) { + seglim = nsegs - seg; + } + for (curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + if (dsp64) { + isp_put_cont64_req(isp, (ispcontreq64_t *)storage, qe1); + } else { + isp_put_cont_req(isp, (ispcontreq_t *)storage, qe1); + } + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "additional queue entry", QENTRY_LEN, storage); + } + nqe++; + } + +copy_and_sync: + ((isphdr_t *)fqe)->rqs_entry_count = nqe; + switch (type) { + case RQSTYPE_REQUEST: + ((ispreq_t *)fqe)->req_flags |= ddf; + /* + * This is historical and not clear whether really needed. + */ + if (nsegs == 0) { + nsegs = 1; + } + ((ispreq_t *)fqe)->req_seg_count = nsegs; + isp_put_request(isp, fqe, qe0); + break; + case RQSTYPE_CMDONLY: + ((ispreq_t *)fqe)->req_flags |= ddf; + /* + * This is historical and not clear whether really needed. + */ + if (nsegs == 0) { + nsegs = 1; + } + ((ispextreq_t *)fqe)->req_seg_count = nsegs; + isp_put_extended_request(isp, fqe, qe0); + break; + case RQSTYPE_T2RQS: + ((ispreqt2_t *)fqe)->req_flags |= ddf; + ((ispreqt2_t *)fqe)->req_seg_count = nsegs; + ((ispreqt2_t *)fqe)->req_totalcnt = totalcnt; + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_request_t2e(isp, fqe, qe0); + } else { + isp_put_request_t2(isp, fqe, qe0); + } + break; + case RQSTYPE_A64: + case RQSTYPE_T3RQS: + ((ispreqt3_t *)fqe)->req_flags |= ddf; + ((ispreqt3_t *)fqe)->req_seg_count = nsegs; + ((ispreqt3_t *)fqe)->req_totalcnt = totalcnt; + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_request_t3e(isp, fqe, qe0); + } else { + isp_put_request_t3(isp, fqe, qe0); + } + break; + case RQSTYPE_T7RQS: + ((ispreqt7_t *)fqe)->req_alen_datadir = ddf; + ((ispreqt7_t *)fqe)->req_seg_count = nsegs; + ((ispreqt7_t *)fqe)->req_dl = totalcnt; + isp_put_request_t7(isp, fqe, qe0); + break; + default: + return (CMD_COMPLETE); + } + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "first queue entry", QENTRY_LEN, fqe); + } + ISP_ADD_REQUEST(isp, nxt); + return (CMD_QUEUED); +} + int isp_save_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep) { @@ -110,29 +308,25 @@ isp_destroy_handle(ispsoftc_t *isp, uint32_t handle) } } -int -isp_getrqentry(ispsoftc_t *isp, uint32_t *iptrp, - uint32_t *optrp, void **resultp) +/* + * Make sure we have space to put something on the request queue. + * Return a pointer to that entry if we do. A side effect of this + * function is to update the output index. The input index + * stays the same. + */ +void * +isp_getrqentry(ispsoftc_t *isp) { - volatile uint32_t iptr, optr; - - optr = isp->isp_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); - iptr = isp->isp_reqidx; - *resultp = ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); - iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN(isp)); - if (iptr == optr) { - return (1); + isp->isp_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); + if (ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)) == isp->isp_reqodx) { + return (NULL); } - if (optrp) - *optrp = optr; - if (iptrp) - *iptrp = iptr; - return (0); + return (ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx)); } #define TBA (4 * (((QENTRY_LEN >> 2) * 3) + 1) + 1) void -isp_print_qentry(ispsoftc_t *isp, char *msg, int idx, void *arg) +isp_print_qentry(ispsoftc_t *isp, const char *msg, int idx, void *arg) { char buf[TBA]; int amt, i, j; @@ -141,9 +335,9 @@ isp_print_qentry(ispsoftc_t *isp, char *msg, int idx, void *arg) isp_prt(isp, ISP_LOGALL, "%s index %d=>", msg, idx); for (buf[0] = 0, amt = i = 0; i < 4; i++) { buf[0] = 0; - SNPRINTF(buf, TBA, " "); + ISP_SNPRINTF(buf, TBA, " "); for (j = 0; j < (QENTRY_LEN >> 2); j++) { - SNPRINTF(buf, TBA, "%s %02x", buf, ptr[amt++] & 0xff); + ISP_SNPRINTF(buf, TBA, "%s %02x", buf, ptr[amt++] & 0xff); } isp_prt(isp, ISP_LOGALL, buf); } @@ -164,9 +358,10 @@ isp_print_bytes(ispsoftc_t *isp, const char *msg, int amt, void *arg) int j, to; to = off; for (j = 0; j < 16; j++) { - SNPRINTF(buf, 128, "%s %02x", buf, ptr[off++] & 0xff); - if (off == amt) + ISP_SNPRINTF(buf, 128, "%s %02x", buf, ptr[off++] & 0xff); + if (off == amt) { break; + } } isp_prt(isp, ISP_LOGALL, "0x%08x:%s", to, buf); buf[0] = 0; @@ -186,62 +381,55 @@ isp_print_bytes(ispsoftc_t *isp, const char *msg, int amt, void *arg) */ int -isp_fc_runstate(ispsoftc_t *isp, int tval) +isp_fc_runstate(ispsoftc_t *isp, int chan, int tval) { fcparam *fcp; - int *tptr; - if (isp->isp_role == ISP_ROLE_NONE) { + fcp = FCPARAM(isp, chan); + if (fcp->role == ISP_ROLE_NONE) { return (0); } - fcp = FCPARAM(isp); - tptr = &tval; - if (fcp->isp_fwstate < FW_READY || - fcp->isp_loopstate < LOOP_PDB_RCVD) { - if (isp_control(isp, ISPCTL_FCLINK_TEST, tptr) != 0) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fc_runstate: linktest failed"); + if (fcp->isp_fwstate < FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) { + if (isp_control(isp, ISPCTL_FCLINK_TEST, chan, tval) != 0) { + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: linktest failed for channel %d", chan); return (-1); } - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate < LOOP_PDB_RCVD) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fc_runstate: f/w not ready"); + if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) { + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: f/w not ready for channel %d", chan); return (-1); } } - if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { + + if ((fcp->role & ISP_ROLE_INITIATOR) == 0) { return (0); } - if (isp_control(isp, ISPCTL_SCAN_LOOP, NULL) != 0) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fc_runstate: scan loop fails"); + + if (isp_control(isp, ISPCTL_SCAN_LOOP, chan) != 0) { + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: scan loop fails on channel %d", chan); return (LOOP_PDB_RCVD); } - if (isp_control(isp, ISPCTL_SCAN_FABRIC, NULL) != 0) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fc_runstate: scan fabric fails"); + if (isp_control(isp, ISPCTL_SCAN_FABRIC, chan) != 0) { + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: scan fabric fails on channel %d", chan); return (LOOP_LSCAN_DONE); } - if (isp_control(isp, ISPCTL_PDB_SYNC, NULL) != 0) { - isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: pdb_sync fails"); + if (isp_control(isp, ISPCTL_PDB_SYNC, chan) != 0) { + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: pdb_sync fails on channel %d", chan); return (LOOP_FSCAN_DONE); } if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_READY) { - isp_prt(isp, ISP_LOGSANCFG, - "isp_fc_runstate: f/w not ready again"); + isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: f/w not ready again on channel %d", chan); return (-1); } return (0); } /* - * Fibre Channel Support- get the port database for the id. + * Fibre Channel Support routines */ void -isp_dump_portdb(ispsoftc_t *isp) +isp_dump_portdb(ispsoftc_t *isp, int chan) { - fcparam *fcp = (fcparam *) isp->isp_param; + fcparam *fcp = FCPARAM(isp, chan); int i; for (i = 0; i < MAX_FC_TARG; i++) { @@ -261,27 +449,249 @@ isp_dump_portdb(ispsoftc_t *isp) }; fcportdb_t *lp = &fcp->portdb[i]; - if (lp->state == FC_PORTDB_STATE_NIL) { + if (lp->state == FC_PORTDB_STATE_NIL && lp->target_mode == 0) { continue; } - if (lp->ini_map_idx) { - SNPRINTF(mb, sizeof (mb), "%3d", - ((int) lp->ini_map_idx) - 1); + if (lp->dev_map_idx) { + ISP_SNPRINTF(mb, sizeof (mb), "%3d", ((int) lp->dev_map_idx) - 1); } else { - SNPRINTF(mb, sizeof (mb), "---"); + ISP_SNPRINTF(mb, sizeof (mb), "---"); } - isp_prt(isp, ISP_LOGALL, "%d: hdl 0x%x %s al%d tgt %s %s " - "0x%06x =>%s 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x", i, - lp->handle, dbs[lp->state], lp->autologin, mb, - roles[lp->roles], lp->portid, - roles[lp->new_roles], lp->new_portid, - (uint32_t) (lp->node_wwn >> 32), - (uint32_t) (lp->node_wwn), - (uint32_t) (lp->port_wwn >> 32), - (uint32_t) (lp->port_wwn)); + isp_prt(isp, ISP_LOGALL, "Chan %d [%d]: hdl 0x%x %s al%d tgt %s %s 0x%06x =>%s 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x", + chan, i, lp->handle, dbs[lp->state], lp->autologin, mb, roles[lp->roles], lp->portid, roles[lp->new_roles], lp->new_portid, + (uint32_t) (lp->node_wwn >> 32), (uint32_t) (lp->node_wwn), (uint32_t) (lp->port_wwn >> 32), (uint32_t) (lp->port_wwn)); } } +const char * +isp_fc_fw_statename(int state) +{ + switch (state) { + case FW_CONFIG_WAIT: return "Config Wait"; + case FW_WAIT_AL_PA: return "Waiting for AL_PA"; + case FW_WAIT_LOGIN: return "Wait Login"; + case FW_READY: return "Ready"; + case FW_LOSS_OF_SYNC: return "Loss Of Sync"; + case FW_ERROR: return "Error"; + case FW_REINIT: return "Re-Init"; + case FW_NON_PART: return "Nonparticipating"; + default: return "?????"; + } +} + +const char * +isp_fc_loop_statename(int state) +{ + switch (state) { + case LOOP_NIL: return "NIL"; + case LOOP_LIP_RCVD: return "LIP Received"; + case LOOP_PDB_RCVD: return "PDB Received"; + case LOOP_SCANNING_LOOP: return "Scanning"; + case LOOP_LSCAN_DONE: return "Loop Scan Done"; + case LOOP_SCANNING_FABRIC: return "Scanning Fabric"; + case LOOP_FSCAN_DONE: return "Fabric Scan Done"; + case LOOP_SYNCING_PDB: return "Syncing PDB"; + case LOOP_READY: return "Ready"; + default: return "?????"; + } +} + +const char * +isp_fc_toponame(fcparam *fcp) +{ + + if (fcp->isp_fwstate != FW_READY) { + return "Unavailable"; + } + switch (fcp->isp_topo) { + case TOPO_NL_PORT: return "Private Loop"; + case TOPO_FL_PORT: return "FL Port"; + case TOPO_N_PORT: return "N-Port to N-Port"; + case TOPO_F_PORT: return "F Port"; + case TOPO_PTP_STUB: return "F Port (no FLOGI_ACC response)"; + default: return "?????"; + } +} + +/* + * Change Roles + */ +int +isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role) +{ + fcparam *fcp = FCPARAM(isp, chan); + + if (chan >= isp->isp_nchan) { + isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan); + return (ENXIO); + } + if (chan == 0) { +#ifdef ISP_TARGET_MODE + isp_del_all_wwn_entries(isp, chan); +#endif + isp_clear_commands(isp); + + isp_reset(isp, 0); + if (isp->isp_state != ISP_RESETSTATE) { + isp_prt(isp, ISP_LOGERR, "%s: cannot reset card", __func__); + return (EIO); + } + fcp->role = new_role; + isp_init(isp); + if (isp->isp_state != ISP_INITSTATE) { + isp_prt(isp, ISP_LOGERR, "%s: cannot init card", __func__); + return (EIO); + } + isp->isp_state = ISP_RUNSTATE; + return (0); + } else if (ISP_CAP_MULTI_ID(isp)) { + mbreg_t mbs; + vp_modify_t *vp; + uint8_t qe[QENTRY_LEN], *scp; + + ISP_MEMZERO(qe, QENTRY_LEN); + /* Acquire Scratch */ + + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + return (EBUSY); + } + scp = fcp->isp_scratch; + + /* + * Build a VP MODIFY command in memory + */ + vp = (vp_modify_t *) qe; + vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY; + vp->vp_mod_hdr.rqs_entry_count = 1; + vp->vp_mod_cnt = 1; + vp->vp_mod_idx0 = chan; + vp->vp_mod_cmd = VP_MODIFY_ENA; + vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED; + if (new_role & ISP_ROLE_INITIATOR) { + vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE; + } + if ((new_role & ISP_ROLE_TARGET) == 0) { + vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE; + } + MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn); + MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn); + isp_put_vp_modify(isp, vp, (vp_modify_t *) scp); + + /* + * Build a EXEC IOCB A64 command that points to the VP MODIFY command + */ + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN); + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp, chan); + return (EIO); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN); + isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp); + +#ifdef ISP_TARGET_MODE + isp_del_all_wwn_entries(isp, chan); +#endif + /* + * Release Scratch + */ + FC_SCRATCH_RELEASE(isp, chan); + + if (vp->vp_mod_status != VP_STS_OK) { + isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status); + return (EIO); + } + fcp->role = new_role; + return (0); + } else { + return (EINVAL); + } +} + +void +isp_clear_commands(ispsoftc_t *isp) +{ + XS_T *xs; + uint32_t tmp, handle; +#ifdef ISP_TARGET_MODE + isp_notify_t notify; +#endif + + for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) { + xs = isp->isp_xflist[tmp]; + if (xs == NULL) { + continue; + } + handle = isp_find_handle(isp, xs); + if (handle == 0) { + continue; + } + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, handle); + XS_SET_RESID(xs, XS_XFRLEN(xs)); + } else { + XS_SET_RESID(xs, 0); + } + isp_destroy_handle(isp, handle); + XS_SETERR(xs, HBA_BUSRESET); + isp_done(xs); + } +#ifdef ISP_TARGET_MODE + for (tmp = 0; isp->isp_tgtlist && tmp < isp->isp_maxcmds; tmp++) { + uint8_t local[QENTRY_LEN]; + + xs = isp->isp_tgtlist[tmp]; + if (xs == NULL) { + continue; + } + handle = isp_find_tgt_handle(isp, xs); + if (handle == 0) { + continue; + } + ISP_DMAFREE(isp, xs, handle); + + ISP_MEMZERO(local, QENTRY_LEN); + if (IS_24XX(isp)) { + ct7_entry_t *ctio = (ct7_entry_t *) local; + ctio->ct_syshandle = handle; + ctio->ct_nphdl = CT_HBA_RESET; + ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + } else if (IS_FC(isp)) { + ct2_entry_t *ctio = (ct2_entry_t *) local; + ctio->ct_syshandle = handle; + ctio->ct_status = CT_HBA_RESET; + ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2; + } else { + ct_entry_t *ctio = (ct_entry_t *) local; + ctio->ct_syshandle = handle & 0xffff; + ctio->ct_status = CT_HBA_RESET & 0xff;; + ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO; + } + isp_async(isp, ISPASYNC_TARGET_ACTION, local); + } + for (tmp = 0; tmp < isp->isp_nchan; tmp++) { + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_ncode = NT_HBA_RESET; + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = NIL_HANDLE; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_tgt = TGT_ANY; + notify.nt_channel = tmp; + notify.nt_lun = LUN_ANY; + notify.nt_tagval = TAG_ANY; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + } +#endif +} + void isp_shutdown(ispsoftc_t *isp) { @@ -315,8 +725,7 @@ isp_shutdown(ispsoftc_t *isp) * (with a few exceptions for efficiency). */ -#define ISP_IS_SBUS(isp) \ - (ISP_SBUS_SUPPORTED && (isp)->isp_bustype == ISP_BT_SBUS) +#define ISP_IS_SBUS(isp) (ISP_SBUS_SUPPORTED && (isp)->isp_bustype == ISP_BT_SBUS) #define ASIZE(x) (sizeof (x) / sizeof (x[0])) /* @@ -326,23 +735,15 @@ void isp_put_hdr(ispsoftc_t *isp, isphdr_t *hpsrc, isphdr_t *hpdst) { if (ISP_IS_SBUS(isp)) { - ISP_IOXPUT_8(isp, hpsrc->rqs_entry_type, - &hpdst->rqs_entry_count); - ISP_IOXPUT_8(isp, hpsrc->rqs_entry_count, - &hpdst->rqs_entry_type); - ISP_IOXPUT_8(isp, hpsrc->rqs_seqno, - &hpdst->rqs_flags); - ISP_IOXPUT_8(isp, hpsrc->rqs_flags, - &hpdst->rqs_seqno); + ISP_IOXPUT_8(isp, hpsrc->rqs_entry_type, &hpdst->rqs_entry_count); + ISP_IOXPUT_8(isp, hpsrc->rqs_entry_count, &hpdst->rqs_entry_type); + ISP_IOXPUT_8(isp, hpsrc->rqs_seqno, &hpdst->rqs_flags); + ISP_IOXPUT_8(isp, hpsrc->rqs_flags, &hpdst->rqs_seqno); } else { - ISP_IOXPUT_8(isp, hpsrc->rqs_entry_type, - &hpdst->rqs_entry_type); - ISP_IOXPUT_8(isp, hpsrc->rqs_entry_count, - &hpdst->rqs_entry_count); - ISP_IOXPUT_8(isp, hpsrc->rqs_seqno, - &hpdst->rqs_seqno); - ISP_IOXPUT_8(isp, hpsrc->rqs_flags, - &hpdst->rqs_flags); + ISP_IOXPUT_8(isp, hpsrc->rqs_entry_type, &hpdst->rqs_entry_type); + ISP_IOXPUT_8(isp, hpsrc->rqs_entry_count, &hpdst->rqs_entry_count); + ISP_IOXPUT_8(isp, hpsrc->rqs_seqno, &hpdst->rqs_seqno); + ISP_IOXPUT_8(isp, hpsrc->rqs_flags, &hpdst->rqs_flags); } } @@ -350,23 +751,15 @@ void isp_get_hdr(ispsoftc_t *isp, isphdr_t *hpsrc, isphdr_t *hpdst) { if (ISP_IS_SBUS(isp)) { - ISP_IOXGET_8(isp, &hpsrc->rqs_entry_type, - hpdst->rqs_entry_count); - ISP_IOXGET_8(isp, &hpsrc->rqs_entry_count, - hpdst->rqs_entry_type); - ISP_IOXGET_8(isp, &hpsrc->rqs_seqno, - hpdst->rqs_flags); - ISP_IOXGET_8(isp, &hpsrc->rqs_flags, - hpdst->rqs_seqno); + ISP_IOXGET_8(isp, &hpsrc->rqs_entry_type, hpdst->rqs_entry_count); + ISP_IOXGET_8(isp, &hpsrc->rqs_entry_count, hpdst->rqs_entry_type); + ISP_IOXGET_8(isp, &hpsrc->rqs_seqno, hpdst->rqs_flags); + ISP_IOXGET_8(isp, &hpsrc->rqs_flags, hpdst->rqs_seqno); } else { - ISP_IOXGET_8(isp, &hpsrc->rqs_entry_type, - hpdst->rqs_entry_type); - ISP_IOXGET_8(isp, &hpsrc->rqs_entry_count, - hpdst->rqs_entry_count); - ISP_IOXGET_8(isp, &hpsrc->rqs_seqno, - hpdst->rqs_seqno); - ISP_IOXGET_8(isp, &hpsrc->rqs_flags, - hpdst->rqs_flags); + ISP_IOXGET_8(isp, &hpsrc->rqs_entry_type, hpdst->rqs_entry_type); + ISP_IOXGET_8(isp, &hpsrc->rqs_entry_count, hpdst->rqs_entry_count); + ISP_IOXGET_8(isp, &hpsrc->rqs_seqno, hpdst->rqs_seqno); + ISP_IOXGET_8(isp, &hpsrc->rqs_flags, hpdst->rqs_flags); } } @@ -403,10 +796,8 @@ isp_put_request(ispsoftc_t *isp, ispreq_t *rqsrc, ispreq_t *rqdst) ISP_IOXPUT_8(isp, rqsrc->req_cdb[i], &rqdst->req_cdb[i]); } for (i = 0; i < ISP_RQDSEG; i++) { - ISP_IOXPUT_32(isp, rqsrc->req_dataseg[i].ds_base, - &rqdst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, rqsrc->req_dataseg[i].ds_count, - &rqdst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, rqsrc->req_dataseg[i].ds_base, &rqdst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, rqsrc->req_dataseg[i].ds_count, &rqdst->req_dataseg[i].ds_count); } } @@ -427,14 +818,12 @@ isp_put_marker(ispsoftc_t *isp, isp_marker_t *src, isp_marker_t *dst) ISP_IOXPUT_16(isp, src->mrk_flags, &dst->mrk_flags); ISP_IOXPUT_16(isp, src->mrk_lun, &dst->mrk_lun); for (i = 0; i < ASIZE(src->mrk_reserved1); i++) { - ISP_IOXPUT_8(isp, src->mrk_reserved1[i], - &dst->mrk_reserved1[i]); + ISP_IOXPUT_8(isp, src->mrk_reserved1[i], &dst->mrk_reserved1[i]); } } void -isp_put_marker_24xx(ispsoftc_t *isp, - isp_marker_24xx_t *src, isp_marker_24xx_t *dst) +isp_put_marker_24xx(ispsoftc_t *isp, isp_marker_24xx_t *src, isp_marker_24xx_t *dst) { int i; isp_put_hdr(isp, &src->mrk_header, &dst->mrk_header); @@ -449,8 +838,7 @@ isp_put_marker_24xx(ispsoftc_t *isp, ISP_IOXPUT_8(isp, src->mrk_lun[i], &dst->mrk_lun[i]); } for (i = 0; i < ASIZE(src->mrk_reserved3); i++) { - ISP_IOXPUT_8(isp, src->mrk_reserved3[i], - &dst->mrk_reserved3[i]); + ISP_IOXPUT_8(isp, src->mrk_reserved3[i], &dst->mrk_reserved3[i]); } } @@ -472,10 +860,8 @@ isp_put_request_t2(ispsoftc_t *isp, ispreqt2_t *src, ispreqt2_t *dst) } ISP_IOXPUT_32(isp, src->req_totalcnt, &dst->req_totalcnt); for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -496,10 +882,8 @@ isp_put_request_t2e(ispsoftc_t *isp, ispreqt2e_t *src, ispreqt2e_t *dst) } ISP_IOXPUT_32(isp, src->req_totalcnt, &dst->req_totalcnt); for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -521,12 +905,9 @@ isp_put_request_t3(ispsoftc_t *isp, ispreqt3_t *src, ispreqt3_t *dst) } ISP_IOXPUT_32(isp, src->req_totalcnt, &dst->req_totalcnt); for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, - &dst->req_dataseg[i].ds_basehi); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, &dst->req_dataseg[i].ds_basehi); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -547,12 +928,9 @@ isp_put_request_t3e(ispsoftc_t *isp, ispreqt3e_t *src, ispreqt3e_t *dst) } ISP_IOXPUT_32(isp, src->req_totalcnt, &dst->req_totalcnt); for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, - &dst->req_dataseg[i].ds_basehi); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, &dst->req_dataseg[i].ds_basehi); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -608,12 +986,40 @@ isp_put_request_t7(ispsoftc_t *isp, ispreqt7_t *src, ispreqt7_t *dst) ISP_IOXPUT_16(isp, src->req_tidlo, &dst->req_tidlo); ISP_IOXPUT_8(isp, src->req_tidhi, &dst->req_tidhi); ISP_IOXPUT_8(isp, src->req_vpidx, &dst->req_vpidx); - ISP_IOXPUT_32(isp, src->req_dataseg.ds_base, - &dst->req_dataseg.ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg.ds_basehi, - &dst->req_dataseg.ds_basehi); - ISP_IOXPUT_32(isp, src->req_dataseg.ds_count, - &dst->req_dataseg.ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg.ds_base, &dst->req_dataseg.ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg.ds_basehi, &dst->req_dataseg.ds_basehi); + ISP_IOXPUT_32(isp, src->req_dataseg.ds_count, &dst->req_dataseg.ds_count); +} + +void +isp_put_24xx_tmf(ispsoftc_t *isp, isp24xx_tmf_t *src, isp24xx_tmf_t *dst) +{ + int i; + uint32_t *a, *b; + + isp_put_hdr(isp, &src->tmf_header, &dst->tmf_header); + ISP_IOXPUT_32(isp, src->tmf_handle, &dst->tmf_handle); + ISP_IOXPUT_16(isp, src->tmf_nphdl, &dst->tmf_nphdl); + ISP_IOXPUT_16(isp, src->tmf_delay, &dst->tmf_delay); + ISP_IOXPUT_16(isp, src->tmf_timeout, &dst->tmf_timeout); + for (i = 0; i < ASIZE(src->tmf_reserved0); i++) { + ISP_IOXPUT_8(isp, src->tmf_reserved0[i], &dst->tmf_reserved0[i]); + } + a = (uint32_t *) src->tmf_lun; + b = (uint32_t *) dst->tmf_lun; + for (i = 0; i < (ASIZE(src->tmf_lun) >> 2); i++ ) { + *b++ = ISP_SWAP32(isp, *a++); + } + ISP_IOXPUT_32(isp, src->tmf_flags, &dst->tmf_flags); + for (i = 0; i < ASIZE(src->tmf_reserved1); i++) { + ISP_IOXPUT_8(isp, src->tmf_reserved1[i], &dst->tmf_reserved1[i]); + } + ISP_IOXPUT_16(isp, src->tmf_tidlo, &dst->tmf_tidlo); + ISP_IOXPUT_8(isp, src->tmf_tidhi, &dst->tmf_tidhi); + ISP_IOXPUT_8(isp, src->tmf_vpidx, &dst->tmf_vpidx); + for (i = 0; i < ASIZE(src->tmf_reserved2); i++) { + ISP_IOXPUT_8(isp, src->tmf_reserved2[i], &dst->tmf_reserved2[i]); + } } void @@ -626,15 +1032,13 @@ isp_put_24xx_abrt(ispsoftc_t *isp, isp24xx_abrt_t *src, isp24xx_abrt_t *dst) ISP_IOXPUT_16(isp, src->abrt_options, &dst->abrt_options); ISP_IOXPUT_32(isp, src->abrt_cmd_handle, &dst->abrt_cmd_handle); for (i = 0; i < ASIZE(src->abrt_reserved); i++) { - ISP_IOXPUT_8(isp, src->abrt_reserved[i], - &dst->abrt_reserved[i]); + ISP_IOXPUT_8(isp, src->abrt_reserved[i], &dst->abrt_reserved[i]); } ISP_IOXPUT_16(isp, src->abrt_tidlo, &dst->abrt_tidlo); ISP_IOXPUT_8(isp, src->abrt_tidhi, &dst->abrt_tidhi); ISP_IOXPUT_8(isp, src->abrt_vpidx, &dst->abrt_vpidx); for (i = 0; i < ASIZE(src->abrt_reserved1); i++) { - ISP_IOXPUT_8(isp, src->abrt_reserved1[i], - &dst->abrt_reserved1[i]); + ISP_IOXPUT_8(isp, src->abrt_reserved1[i], &dst->abrt_reserved1[i]); } } @@ -644,10 +1048,8 @@ isp_put_cont_req(ispsoftc_t *isp, ispcontreq_t *src, ispcontreq_t *dst) int i; isp_put_hdr(isp, &src->req_header, &dst->req_header); for (i = 0; i < ISP_CDSEG; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -657,12 +1059,9 @@ isp_put_cont64_req(ispsoftc_t *isp, ispcontreq64_t *src, ispcontreq64_t *dst) int i; isp_put_hdr(isp, &src->req_header, &dst->req_header); for (i = 0; i < ISP_CDSEG64; i++) { - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, - &dst->req_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, - &dst->req_dataseg[i].ds_basehi); - ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, - &dst->req_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_base, &dst->req_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_basehi, &dst->req_dataseg[i].ds_basehi); + ISP_IOXPUT_32(isp, src->req_dataseg[i].ds_count, &dst->req_dataseg[i].ds_count); } } @@ -673,34 +1072,29 @@ isp_get_response(ispsoftc_t *isp, ispstatusreq_t *src, ispstatusreq_t *dst) isp_get_hdr(isp, &src->req_header, &dst->req_header); ISP_IOXGET_32(isp, &src->req_handle, dst->req_handle); ISP_IOXGET_16(isp, &src->req_scsi_status, dst->req_scsi_status); - ISP_IOXGET_16(isp, &src->req_completion_status, - dst->req_completion_status); + ISP_IOXGET_16(isp, &src->req_completion_status, dst->req_completion_status); ISP_IOXGET_16(isp, &src->req_state_flags, dst->req_state_flags); ISP_IOXGET_16(isp, &src->req_status_flags, dst->req_status_flags); ISP_IOXGET_16(isp, &src->req_time, dst->req_time); ISP_IOXGET_16(isp, &src->req_sense_len, dst->req_sense_len); ISP_IOXGET_32(isp, &src->req_resid, dst->req_resid); for (i = 0; i < 8; i++) { - ISP_IOXGET_8(isp, &src->req_response[i], - dst->req_response[i]); + ISP_IOXGET_8(isp, &src->req_response[i], dst->req_response[i]); } for (i = 0; i < 32; i++) { - ISP_IOXGET_8(isp, &src->req_sense_data[i], - dst->req_sense_data[i]); + ISP_IOXGET_8(isp, &src->req_sense_data[i], dst->req_sense_data[i]); } } void -isp_get_24xx_response(ispsoftc_t *isp, isp24xx_statusreq_t *src, - isp24xx_statusreq_t *dst) +isp_get_24xx_response(ispsoftc_t *isp, isp24xx_statusreq_t *src, isp24xx_statusreq_t *dst) { int i; uint32_t *s, *d; isp_get_hdr(isp, &src->req_header, &dst->req_header); ISP_IOXGET_32(isp, &src->req_handle, dst->req_handle); - ISP_IOXGET_16(isp, &src->req_completion_status, - dst->req_completion_status); + ISP_IOXGET_16(isp, &src->req_completion_status, dst->req_completion_status); ISP_IOXGET_16(isp, &src->req_oxid, dst->req_oxid); ISP_IOXGET_32(isp, &src->req_resid, dst->req_resid); ISP_IOXGET_16(isp, &src->req_reserved0, dst->req_reserved0); @@ -727,15 +1121,13 @@ isp_get_24xx_abrt(ispsoftc_t *isp, isp24xx_abrt_t *src, isp24xx_abrt_t *dst) ISP_IOXGET_16(isp, &src->abrt_options, dst->abrt_options); ISP_IOXGET_32(isp, &src->abrt_cmd_handle, dst->abrt_cmd_handle); for (i = 0; i < ASIZE(src->abrt_reserved); i++) { - ISP_IOXGET_8(isp, &src->abrt_reserved[i], - dst->abrt_reserved[i]); + ISP_IOXGET_8(isp, &src->abrt_reserved[i], dst->abrt_reserved[i]); } ISP_IOXGET_16(isp, &src->abrt_tidlo, dst->abrt_tidlo); ISP_IOXGET_8(isp, &src->abrt_tidhi, dst->abrt_tidhi); ISP_IOXGET_8(isp, &src->abrt_vpidx, dst->abrt_vpidx); for (i = 0; i < ASIZE(src->abrt_reserved1); i++) { - ISP_IOXGET_8(isp, &src->abrt_reserved1[i], - dst->abrt_reserved1[i]); + ISP_IOXGET_8(isp, &src->abrt_reserved1[i], dst->abrt_reserved1[i]); } } @@ -749,8 +1141,7 @@ isp_get_rio2(ispsoftc_t *isp, isp_rio2_t *r2src, isp_rio2_t *r2dst) r2dst->req_header.rqs_seqno = 30; } for (i = 0; i < r2dst->req_header.rqs_seqno; i++) { - ISP_IOXGET_16(isp, &r2src->req_handles[i], - r2dst->req_handles[i]); + ISP_IOXGET_16(isp, &r2src->req_handles[i], r2dst->req_handles[i]); } while (i < 30) { r2dst->req_handles[i++] = 0; @@ -858,14 +1249,12 @@ isp_put_icb_2400(ispsoftc_t *isp, isp_icb_2400_t *src, isp_icb_2400_t *dst) ISP_IOXPUT_16(isp, src->icb_priaddr[i], &dst->icb_priaddr[i]); } for (i = 0; i < 4; i++) { - ISP_IOXPUT_16(isp, src->icb_reserved1[i], - &dst->icb_reserved1[i]); + ISP_IOXPUT_16(isp, src->icb_reserved1[i], &dst->icb_reserved1[i]); } ISP_IOXPUT_16(isp, src->icb_atio_in, &dst->icb_atio_in); ISP_IOXPUT_16(isp, src->icb_atioqlen, &dst->icb_atioqlen); for (i = 0; i < 4; i++) { - ISP_IOXPUT_16(isp, src->icb_atioqaddr[i], - &dst->icb_atioqaddr[i]); + ISP_IOXPUT_16(isp, src->icb_atioqaddr[i], &dst->icb_atioqaddr[i]); } ISP_IOXPUT_16(isp, src->icb_idelaytimer, &dst->icb_idelaytimer); ISP_IOXPUT_16(isp, src->icb_logintime, &dst->icb_logintime); @@ -873,8 +1262,139 @@ isp_put_icb_2400(ispsoftc_t *isp, isp_icb_2400_t *src, isp_icb_2400_t *dst) ISP_IOXPUT_32(isp, src->icb_fwoptions2, &dst->icb_fwoptions2); ISP_IOXPUT_32(isp, src->icb_fwoptions3, &dst->icb_fwoptions3); for (i = 0; i < 12; i++) { - ISP_IOXPUT_16(isp, src->icb_reserved2[i], - &dst->icb_reserved2[i]); + ISP_IOXPUT_16(isp, src->icb_reserved2[i], &dst->icb_reserved2[i]); + } +} + +void +isp_put_icb_2400_vpinfo(ispsoftc_t *isp, isp_icb_2400_vpinfo_t *src, isp_icb_2400_vpinfo_t *dst) +{ + ISP_IOXPUT_16(isp, src->vp_count, &dst->vp_count); + ISP_IOXPUT_16(isp, src->vp_global_options, &dst->vp_global_options); +} + +void +isp_put_vp_port_info(ispsoftc_t *isp, vp_port_info_t *src, vp_port_info_t *dst) +{ + int i; + ISP_IOXPUT_16(isp, src->vp_port_status, &dst->vp_port_status); + ISP_IOXPUT_8(isp, src->vp_port_options, &dst->vp_port_options); + ISP_IOXPUT_8(isp, src->vp_port_loopid, &dst->vp_port_loopid); + for (i = 0; i < 8; i++) { + ISP_IOXPUT_8(isp, src->vp_port_portname[i], &dst->vp_port_portname[i]); + } + for (i = 0; i < 8; i++) { + ISP_IOXPUT_8(isp, src->vp_port_nodename[i], &dst->vp_port_nodename[i]); + } + /* we never *put* portid_lo/portid_hi */ +} + +void +isp_get_vp_port_info(ispsoftc_t *isp, vp_port_info_t *src, vp_port_info_t *dst) +{ + int i; + ISP_IOXGET_16(isp, &src->vp_port_status, dst->vp_port_status); + ISP_IOXGET_8(isp, &src->vp_port_options, dst->vp_port_options); + ISP_IOXGET_8(isp, &src->vp_port_loopid, dst->vp_port_loopid); + for (i = 0; i < ASIZE(src->vp_port_portname); i++) { + ISP_IOXGET_8(isp, &src->vp_port_portname[i], dst->vp_port_portname[i]); + } + for (i = 0; i < ASIZE(src->vp_port_nodename); i++) { + ISP_IOXGET_8(isp, &src->vp_port_nodename[i], dst->vp_port_nodename[i]); + } + ISP_IOXGET_16(isp, &src->vp_port_portid_lo, dst->vp_port_portid_lo); + ISP_IOXGET_16(isp, &src->vp_port_portid_hi, dst->vp_port_portid_hi); +} + +void +isp_put_vp_ctrl_info(ispsoftc_t *isp, vp_ctrl_info_t *src, vp_ctrl_info_t *dst) +{ + int i; + isp_put_hdr(isp, &src->vp_ctrl_hdr, &dst->vp_ctrl_hdr); + ISP_IOXPUT_32(isp, src->vp_ctrl_handle, &dst->vp_ctrl_handle); + ISP_IOXPUT_16(isp, src->vp_ctrl_index_fail, &dst->vp_ctrl_index_fail); + ISP_IOXPUT_16(isp, src->vp_ctrl_status, &dst->vp_ctrl_status); + ISP_IOXPUT_16(isp, src->vp_ctrl_command, &dst->vp_ctrl_command); + ISP_IOXPUT_16(isp, src->vp_ctrl_vp_count, &dst->vp_ctrl_vp_count); + for (i = 0; i < ASIZE(src->vp_ctrl_idmap); i++) { + ISP_IOXPUT_16(isp, src->vp_ctrl_idmap[i], &dst->vp_ctrl_idmap[i]); + } + for (i = 0; i < ASIZE(src->vp_ctrl_reserved); i++) { + ISP_IOXPUT_8(isp, src->vp_ctrl_idmap[i], &dst->vp_ctrl_idmap[i]); + } +} + +void +isp_get_vp_ctrl_info(ispsoftc_t *isp, vp_ctrl_info_t *src, vp_ctrl_info_t *dst) +{ + int i; + isp_get_hdr(isp, &src->vp_ctrl_hdr, &dst->vp_ctrl_hdr); + ISP_IOXGET_32(isp, &src->vp_ctrl_handle, dst->vp_ctrl_handle); + ISP_IOXGET_16(isp, &src->vp_ctrl_index_fail, dst->vp_ctrl_index_fail); + ISP_IOXGET_16(isp, &src->vp_ctrl_status, dst->vp_ctrl_status); + ISP_IOXGET_16(isp, &src->vp_ctrl_command, dst->vp_ctrl_command); + ISP_IOXGET_16(isp, &src->vp_ctrl_vp_count, dst->vp_ctrl_vp_count); + for (i = 0; i < ASIZE(src->vp_ctrl_idmap); i++) { + ISP_IOXGET_16(isp, &src->vp_ctrl_idmap[i], dst->vp_ctrl_idmap[i]); + } + for (i = 0; i < ASIZE(src->vp_ctrl_reserved); i++) { + ISP_IOXGET_8(isp, &src->vp_ctrl_reserved[i], dst->vp_ctrl_reserved[i]); + } +} + +void +isp_put_vp_modify(ispsoftc_t *isp, vp_modify_t *src, vp_modify_t *dst) +{ + int i, j; + isp_put_hdr(isp, &src->vp_mod_hdr, &dst->vp_mod_hdr); + ISP_IOXPUT_32(isp, src->vp_mod_hdl, &dst->vp_mod_hdl); + ISP_IOXPUT_16(isp, src->vp_mod_reserved0, &dst->vp_mod_reserved0); + ISP_IOXPUT_16(isp, src->vp_mod_status, &dst->vp_mod_status); + ISP_IOXPUT_8(isp, src->vp_mod_cmd, &dst->vp_mod_cmd); + ISP_IOXPUT_8(isp, src->vp_mod_cnt, &dst->vp_mod_cnt); + ISP_IOXPUT_8(isp, src->vp_mod_idx0, &dst->vp_mod_idx0); + ISP_IOXPUT_8(isp, src->vp_mod_idx1, &dst->vp_mod_idx1); + for (i = 0; i < ASIZE(src->vp_mod_ports); i++) { + ISP_IOXPUT_8(isp, src->vp_mod_ports[i].options, &dst->vp_mod_ports[i].options); + ISP_IOXPUT_8(isp, src->vp_mod_ports[i].loopid, &dst->vp_mod_ports[i].loopid); + ISP_IOXPUT_16(isp, src->vp_mod_ports[i].reserved1, &dst->vp_mod_ports[i].reserved1); + for (j = 0; j < ASIZE(src->vp_mod_ports[i].wwpn); j++) { + ISP_IOXPUT_8(isp, src->vp_mod_ports[i].wwpn[j], &dst->vp_mod_ports[i].wwpn[j]); + } + for (j = 0; j < ASIZE(src->vp_mod_ports[i].wwnn); j++) { + ISP_IOXPUT_8(isp, src->vp_mod_ports[i].wwnn[j], &dst->vp_mod_ports[i].wwnn[j]); + } + } + for (i = 0; i < ASIZE(src->vp_mod_reserved2); i++) { + ISP_IOXPUT_8(isp, src->vp_mod_reserved2[i], &dst->vp_mod_reserved2[i]); + } +} + +void +isp_get_vp_modify(ispsoftc_t *isp, vp_modify_t *src, vp_modify_t *dst) +{ + int i, j; + isp_get_hdr(isp, &src->vp_mod_hdr, &dst->vp_mod_hdr); + ISP_IOXGET_32(isp, &src->vp_mod_hdl, dst->vp_mod_hdl); + ISP_IOXGET_16(isp, &src->vp_mod_reserved0, dst->vp_mod_reserved0); + ISP_IOXGET_16(isp, &src->vp_mod_status, dst->vp_mod_status); + ISP_IOXGET_8(isp, &src->vp_mod_cmd, dst->vp_mod_cmd); + ISP_IOXGET_8(isp, &src->vp_mod_cnt, dst->vp_mod_cnt); + ISP_IOXGET_8(isp, &src->vp_mod_idx0, dst->vp_mod_idx0); + ISP_IOXGET_8(isp, &src->vp_mod_idx1, dst->vp_mod_idx1); + for (i = 0; i < ASIZE(src->vp_mod_ports); i++) { + ISP_IOXGET_8(isp, &src->vp_mod_ports[i].options, dst->vp_mod_ports[i].options); + ISP_IOXGET_8(isp, &src->vp_mod_ports[i].loopid, dst->vp_mod_ports[i].loopid); + ISP_IOXGET_16(isp, &src->vp_mod_ports[i].reserved1, dst->vp_mod_ports[i].reserved1); + for (j = 0; j < ASIZE(src->vp_mod_ports[i].wwpn); j++) { + ISP_IOXGET_8(isp, &src->vp_mod_ports[i].wwpn[j], dst->vp_mod_ports[i].wwpn[j]); + } + for (j = 0; j < ASIZE(src->vp_mod_ports[i].wwnn); j++) { + ISP_IOXGET_8(isp, &src->vp_mod_ports[i].wwnn[j], dst->vp_mod_ports[i].wwnn[j]); + } + } + for (i = 0; i < ASIZE(src->vp_mod_reserved2); i++) { + ISP_IOXGET_8(isp, &src->vp_mod_reserved2[i], dst->vp_mod_reserved2[i]); } } @@ -886,12 +1406,10 @@ isp_get_pdb_21xx(ispsoftc_t *isp, isp_pdb_21xx_t *src, isp_pdb_21xx_t *dst) ISP_IOXGET_8(isp, &src->pdb_mstate, dst->pdb_mstate); ISP_IOXGET_8(isp, &src->pdb_sstate, dst->pdb_sstate); for (i = 0; i < 4; i++) { - ISP_IOXGET_8(isp, &src->pdb_hardaddr_bits[i], - dst->pdb_hardaddr_bits[i]); + ISP_IOXGET_8(isp, &src->pdb_hardaddr_bits[i], dst->pdb_hardaddr_bits[i]); } for (i = 0; i < 4; i++) { - ISP_IOXGET_8(isp, &src->pdb_portid_bits[i], - dst->pdb_portid_bits[i]); + ISP_IOXGET_8(isp, &src->pdb_portid_bits[i], dst->pdb_portid_bits[i]); } for (i = 0; i < 8; i++) { ISP_IOXGET_8(isp, &src->pdb_nodename[i], dst->pdb_nodename[i]); @@ -940,12 +1458,10 @@ isp_get_pdb_24xx(ispsoftc_t *isp, isp_pdb_24xx_t *src, isp_pdb_24xx_t *dst) ISP_IOXGET_8(isp, &src->pdb_curstate, dst->pdb_curstate); ISP_IOXGET_8(isp, &src->pdb_laststate, dst->pdb_laststate); for (i = 0; i < 4; i++) { - ISP_IOXGET_8(isp, &src->pdb_hardaddr_bits[i], - dst->pdb_hardaddr_bits[i]); + ISP_IOXGET_8(isp, &src->pdb_hardaddr_bits[i], dst->pdb_hardaddr_bits[i]); } for (i = 0; i < 4; i++) { - ISP_IOXGET_8(isp, &src->pdb_portid_bits[i], - dst->pdb_portid_bits[i]); + ISP_IOXGET_8(isp, &src->pdb_portid_bits[i], dst->pdb_portid_bits[i]); } ISP_IOXGET_16(isp, &src->pdb_retry_timer, dst->pdb_retry_timer); ISP_IOXGET_16(isp, &src->pdb_handle, dst->pdb_handle); @@ -960,8 +1476,7 @@ isp_get_pdb_24xx(ispsoftc_t *isp, isp_pdb_24xx_t *src, isp_pdb_24xx_t *dst) ISP_IOXGET_8(isp, &src->pdb_portname[i], dst->pdb_portname[i]); } for (i = 0; i < 24; i++) { - ISP_IOXGET_8(isp, &src->pdb_reserved1[i], - dst->pdb_reserved1[i]); + ISP_IOXGET_8(isp, &src->pdb_reserved1[i], dst->pdb_reserved1[i]); } } @@ -982,10 +1497,8 @@ isp_get_plogx(ispsoftc_t *isp, isp_plogx_t *src, isp_plogx_t *dst) ISP_IOXGET_16(isp, &src->plogx_portlo, dst->plogx_portlo); ISP_IOXGET_16(isp, &src->plogx_rspsz_porthi, dst->plogx_rspsz_porthi); for (i = 0; i < 11; i++) { - ISP_IOXGET_16(isp, &src->plogx_ioparm[i].lo16, - dst->plogx_ioparm[i].lo16); - ISP_IOXGET_16(isp, &src->plogx_ioparm[i].hi16, - dst->plogx_ioparm[i].hi16); + ISP_IOXGET_16(isp, &src->plogx_ioparm[i].lo16, dst->plogx_ioparm[i].lo16); + ISP_IOXGET_16(isp, &src->plogx_ioparm[i].hi16, dst->plogx_ioparm[i].hi16); } } @@ -1002,13 +1515,43 @@ isp_put_plogx(ispsoftc_t *isp, isp_plogx_t *src, isp_plogx_t *dst) ISP_IOXPUT_16(isp, src->plogx_portlo, &dst->plogx_portlo); ISP_IOXPUT_16(isp, src->plogx_rspsz_porthi, &dst->plogx_rspsz_porthi); for (i = 0; i < 11; i++) { - ISP_IOXPUT_16(isp, src->plogx_ioparm[i].lo16, - &dst->plogx_ioparm[i].lo16); - ISP_IOXPUT_16(isp, src->plogx_ioparm[i].hi16, - &dst->plogx_ioparm[i].hi16); + ISP_IOXPUT_16(isp, src->plogx_ioparm[i].lo16, &dst->plogx_ioparm[i].lo16); + ISP_IOXPUT_16(isp, src->plogx_ioparm[i].hi16, &dst->plogx_ioparm[i].hi16); } } +/* + * Report ID canonicalization + */ +void +isp_get_ridacq(ispsoftc_t *isp, isp_ridacq_t *src, isp_ridacq_t *dst) +{ + int i; + isp_get_hdr(isp, &src->ridacq_hdr, &dst->ridacq_hdr); + ISP_IOXGET_32(isp, &src->ridacq_handle, dst->ridacq_handle); + ISP_IOXGET_16(isp, &src->ridacq_vp_port_lo, dst->ridacq_vp_port_lo); + ISP_IOXGET_8(isp, &src->ridacq_vp_port_hi, dst->ridacq_vp_port_hi); + ISP_IOXGET_8(isp, &src->ridacq_format, dst->ridacq_format); + for (i = 0; i < sizeof (src->ridacq_map) / sizeof (src->ridacq_map[0]); i++) { + ISP_IOXGET_16(isp, &src->ridacq_map[i], dst->ridacq_map[i]); + } + for (i = 0; i < sizeof (src->ridacq_reserved1) / sizeof (src->ridacq_reserved1[0]); i++) { + ISP_IOXGET_16(isp, &src->ridacq_reserved1[i], dst->ridacq_reserved1[i]); + } + if (dst->ridacq_format == 0) { + ISP_IOXGET_8(isp, &src->un.type0.ridacq_vp_acquired, dst->un.type0.ridacq_vp_acquired); + ISP_IOXGET_8(isp, &src->un.type0.ridacq_vp_setup, dst->un.type0.ridacq_vp_setup); + ISP_IOXGET_16(isp, &src->un.type0.ridacq_reserved0, dst->un.type0.ridacq_reserved0); + } else if (dst->ridacq_format == 1) { + ISP_IOXGET_16(isp, &src->un.type1.ridacq_vp_count, dst->un.type1.ridacq_vp_count); + ISP_IOXGET_8(isp, &src->un.type1.ridacq_vp_index, dst->un.type1.ridacq_vp_index); + ISP_IOXGET_8(isp, &src->un.type1.ridacq_vp_status, dst->un.type1.ridacq_vp_status); + } else { + ISP_MEMZERO(&dst->un, sizeof (dst->un)); + } +} + + /* * CT Passthru canonicalization */ @@ -1022,23 +1565,20 @@ isp_get_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *src, isp_ct_pt_t *dst) ISP_IOXGET_16(isp, &src->ctp_status, dst->ctp_status); ISP_IOXGET_16(isp, &src->ctp_nphdl, dst->ctp_nphdl); ISP_IOXGET_16(isp, &src->ctp_cmd_cnt, dst->ctp_cmd_cnt); - ISP_IOXGET_16(isp, &src->ctp_vpidx, dst->ctp_vpidx); + ISP_IOXGET_8(isp, &src->ctp_vpidx, dst->ctp_vpidx); + ISP_IOXGET_8(isp, &src->ctp_reserved0, dst->ctp_reserved0); ISP_IOXGET_16(isp, &src->ctp_time, dst->ctp_time); - ISP_IOXGET_16(isp, &src->ctp_reserved0, dst->ctp_reserved0); + ISP_IOXGET_16(isp, &src->ctp_reserved1, dst->ctp_reserved1); ISP_IOXGET_16(isp, &src->ctp_rsp_cnt, dst->ctp_rsp_cnt); for (i = 0; i < 5; i++) { - ISP_IOXGET_16(isp, &src->ctp_reserved1[i], - dst->ctp_reserved1[i]); + ISP_IOXGET_16(isp, &src->ctp_reserved2[i], dst->ctp_reserved2[i]); } ISP_IOXGET_32(isp, &src->ctp_rsp_bcnt, dst->ctp_rsp_bcnt); ISP_IOXGET_32(isp, &src->ctp_cmd_bcnt, dst->ctp_cmd_bcnt); for (i = 0; i < 2; i++) { - ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_base, - dst->ctp_dataseg[i].ds_base); - ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_basehi, - dst->ctp_dataseg[i].ds_basehi); - ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_count, - dst->ctp_dataseg[i].ds_count); + ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_base, dst->ctp_dataseg[i].ds_base); + ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_basehi, dst->ctp_dataseg[i].ds_basehi); + ISP_IOXGET_32(isp, &src->ctp_dataseg[i].ds_count, dst->ctp_dataseg[i].ds_count); } } @@ -1063,12 +1603,9 @@ isp_get_ms(ispsoftc_t *isp, isp_ms_t *src, isp_ms_t *dst) ISP_IOXGET_32(isp, &src->ms_rsp_bcnt, dst->ms_rsp_bcnt); ISP_IOXGET_32(isp, &src->ms_cmd_bcnt, dst->ms_cmd_bcnt); for (i = 0; i < 2; i++) { - ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_base, - dst->ms_dataseg[i].ds_base); - ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_basehi, - dst->ms_dataseg[i].ds_basehi); - ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_count, - dst->ms_dataseg[i].ds_count); + ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_base, dst->ms_dataseg[i].ds_base); + ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_basehi, dst->ms_dataseg[i].ds_basehi); + ISP_IOXGET_32(isp, &src->ms_dataseg[i].ds_count, dst->ms_dataseg[i].ds_count); } } @@ -1082,23 +1619,20 @@ isp_put_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *src, isp_ct_pt_t *dst) ISP_IOXPUT_16(isp, src->ctp_status, &dst->ctp_status); ISP_IOXPUT_16(isp, src->ctp_nphdl, &dst->ctp_nphdl); ISP_IOXPUT_16(isp, src->ctp_cmd_cnt, &dst->ctp_cmd_cnt); - ISP_IOXPUT_16(isp, src->ctp_vpidx, &dst->ctp_vpidx); + ISP_IOXPUT_8(isp, src->ctp_vpidx, &dst->ctp_vpidx); + ISP_IOXPUT_8(isp, src->ctp_reserved0, &dst->ctp_reserved0); ISP_IOXPUT_16(isp, src->ctp_time, &dst->ctp_time); - ISP_IOXPUT_16(isp, src->ctp_reserved0, &dst->ctp_reserved0); + ISP_IOXPUT_16(isp, src->ctp_reserved1, &dst->ctp_reserved1); ISP_IOXPUT_16(isp, src->ctp_rsp_cnt, &dst->ctp_rsp_cnt); for (i = 0; i < 5; i++) { - ISP_IOXPUT_16(isp, src->ctp_reserved1[i], - &dst->ctp_reserved1[i]); + ISP_IOXPUT_16(isp, src->ctp_reserved2[i], &dst->ctp_reserved2[i]); } ISP_IOXPUT_32(isp, src->ctp_rsp_bcnt, &dst->ctp_rsp_bcnt); ISP_IOXPUT_32(isp, src->ctp_cmd_bcnt, &dst->ctp_cmd_bcnt); for (i = 0; i < 2; i++) { - ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_base, - &dst->ctp_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_basehi, - &dst->ctp_dataseg[i].ds_basehi); - ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_count, - &dst->ctp_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_base, &dst->ctp_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_basehi, &dst->ctp_dataseg[i].ds_basehi); + ISP_IOXPUT_32(isp, src->ctp_dataseg[i].ds_count, &dst->ctp_dataseg[i].ds_count); } } @@ -1123,12 +1657,9 @@ isp_put_ms(ispsoftc_t *isp, isp_ms_t *src, isp_ms_t *dst) ISP_IOXPUT_32(isp, src->ms_rsp_bcnt, &dst->ms_rsp_bcnt); ISP_IOXPUT_32(isp, src->ms_cmd_bcnt, &dst->ms_cmd_bcnt); for (i = 0; i < 2; i++) { - ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_base, - &dst->ms_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_basehi, - &dst->ms_dataseg[i].ds_basehi); - ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_count, - &dst->ms_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_base, &dst->ms_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_basehi, &dst->ms_dataseg[i].ds_basehi); + ISP_IOXPUT_32(isp, src->ms_dataseg[i].ds_count, &dst->ms_dataseg[i].ds_count); } } @@ -1148,12 +1679,10 @@ isp_put_sns_request(ispsoftc_t *isp, sns_screq_t *src, sns_screq_t *dst) for (i = 0; i < nw; i++) { ISP_IOXPUT_16(isp, src->snscb_data[i], &dst->snscb_data[i]); } - } void -isp_put_gid_ft_request(ispsoftc_t *isp, sns_gid_ft_req_t *src, - sns_gid_ft_req_t *dst) +isp_put_gid_ft_request(ispsoftc_t *isp, sns_gid_ft_req_t *src, sns_gid_ft_req_t *dst) { ISP_IOXPUT_16(isp, src->snscb_rblen, &dst->snscb_rblen); ISP_IOXPUT_16(isp, src->snscb_reserved0, &dst->snscb_reserved0); @@ -1170,8 +1699,7 @@ isp_put_gid_ft_request(ispsoftc_t *isp, sns_gid_ft_req_t *src, } void -isp_put_gxn_id_request(ispsoftc_t *isp, sns_gxn_id_req_t *src, - sns_gxn_id_req_t *dst) +isp_put_gxn_id_request(ispsoftc_t *isp, sns_gxn_id_req_t *src, sns_gxn_id_req_t *dst) { ISP_IOXPUT_16(isp, src->snscb_rblen, &dst->snscb_rblen); ISP_IOXPUT_16(isp, src->snscb_reserved0, &dst->snscb_reserved0); @@ -1192,8 +1720,7 @@ isp_put_gxn_id_request(ispsoftc_t *isp, sns_gxn_id_req_t *src, * isn't always 16 bit words. */ void -isp_get_sns_response(ispsoftc_t *isp, sns_scrsp_t *src, - sns_scrsp_t *dst, int nwords) +isp_get_sns_response(ispsoftc_t *isp, sns_scrsp_t *src, sns_scrsp_t *dst, int nwords) { int i; isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); @@ -1212,20 +1739,15 @@ isp_get_sns_response(ispsoftc_t *isp, sns_scrsp_t *src, } void -isp_get_gid_ft_response(ispsoftc_t *isp, sns_gid_ft_rsp_t *src, - sns_gid_ft_rsp_t *dst, int nwords) +isp_get_gid_ft_response(ispsoftc_t *isp, sns_gid_ft_rsp_t *src, sns_gid_ft_rsp_t *dst, int nwords) { int i; isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); for (i = 0; i < nwords; i++) { int j; - ISP_IOXGET_8(isp, - &src->snscb_ports[i].control, - dst->snscb_ports[i].control); + ISP_IOXGET_8(isp, &src->snscb_ports[i].control, dst->snscb_ports[i].control); for (j = 0; j < 3; j++) { - ISP_IOXGET_8(isp, - &src->snscb_ports[i].portid[j], - dst->snscb_ports[i].portid[j]); + ISP_IOXGET_8(isp, &src->snscb_ports[i].portid[j], dst->snscb_ports[i].portid[j]); } if (dst->snscb_ports[i].control & 0x80) { break; @@ -1234,76 +1756,66 @@ isp_get_gid_ft_response(ispsoftc_t *isp, sns_gid_ft_rsp_t *src, } void -isp_get_gxn_id_response(ispsoftc_t *isp, sns_gxn_id_rsp_t *src, - sns_gxn_id_rsp_t *dst) +isp_get_gxn_id_response(ispsoftc_t *isp, sns_gxn_id_rsp_t *src, sns_gxn_id_rsp_t *dst) { int i; isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { ISP_IOXGET_8(isp, &src->snscb_wwn[i], dst->snscb_wwn[i]); -} - -void -isp_get_gff_id_response(ispsoftc_t *isp, sns_gff_id_rsp_t *src, - sns_gff_id_rsp_t *dst) -{ - int i; - isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); - for (i = 0; i < 32; i++) { - ISP_IOXGET_32(isp, &src->snscb_fc4_features[i], - dst->snscb_fc4_features[i]); } } void -isp_get_ga_nxt_response(ispsoftc_t *isp, sns_ga_nxt_rsp_t *src, - sns_ga_nxt_rsp_t *dst) +isp_get_gff_id_response(ispsoftc_t *isp, sns_gff_id_rsp_t *src, sns_gff_id_rsp_t *dst) +{ + int i; + isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); + for (i = 0; i < 32; i++) { + ISP_IOXGET_32(isp, &src->snscb_fc4_features[i], dst->snscb_fc4_features[i]); + } +} + +void +isp_get_ga_nxt_response(ispsoftc_t *isp, sns_ga_nxt_rsp_t *src, sns_ga_nxt_rsp_t *dst) { int i; isp_get_ct_hdr(isp, &src->snscb_cthdr, &dst->snscb_cthdr); ISP_IOXGET_8(isp, &src->snscb_port_type, dst->snscb_port_type); for (i = 0; i < 3; i++) { - ISP_IOXGET_8(isp, &src->snscb_port_id[i], - dst->snscb_port_id[i]); + ISP_IOXGET_8(isp, &src->snscb_port_id[i], dst->snscb_port_id[i]); } for (i = 0; i < 8; i++) { - ISP_IOXGET_8(isp, &src->snscb_portname[i], - dst->snscb_portname[i]); + ISP_IOXGET_8(isp, &src->snscb_portname[i], dst->snscb_portname[i]); } ISP_IOXGET_8(isp, &src->snscb_pnlen, dst->snscb_pnlen); for (i = 0; i < 255; i++) { ISP_IOXGET_8(isp, &src->snscb_pname[i], dst->snscb_pname[i]); } for (i = 0; i < 8; i++) { - ISP_IOXGET_8(isp, &src->snscb_nodename[i], - dst->snscb_nodename[i]); + ISP_IOXGET_8(isp, &src->snscb_nodename[i], dst->snscb_nodename[i]); } ISP_IOXGET_8(isp, &src->snscb_nnlen, dst->snscb_nnlen); for (i = 0; i < 255; i++) { ISP_IOXGET_8(isp, &src->snscb_nname[i], dst->snscb_nname[i]); } for (i = 0; i < 8; i++) { - ISP_IOXGET_8(isp, &src->snscb_ipassoc[i], - dst->snscb_ipassoc[i]); + ISP_IOXGET_8(isp, &src->snscb_ipassoc[i], dst->snscb_ipassoc[i]); } for (i = 0; i < 16; i++) { ISP_IOXGET_8(isp, &src->snscb_ipaddr[i], dst->snscb_ipaddr[i]); } for (i = 0; i < 4; i++) { - ISP_IOXGET_8(isp, &src->snscb_svc_class[i], - dst->snscb_svc_class[i]); + ISP_IOXGET_8(isp, &src->snscb_svc_class[i], dst->snscb_svc_class[i]); } for (i = 0; i < 32; i++) { - ISP_IOXGET_8(isp, &src->snscb_fc4_types[i], - dst->snscb_fc4_types[i]); + ISP_IOXGET_8(isp, &src->snscb_fc4_types[i], dst->snscb_fc4_types[i]); } for (i = 0; i < 8; i++) { ISP_IOXGET_8(isp, &src->snscb_fpname[i], dst->snscb_fpname[i]); } ISP_IOXGET_8(isp, &src->snscb_reserved, dst->snscb_reserved); for (i = 0; i < 3; i++) { - ISP_IOXGET_8(isp, &src->snscb_hardaddr[i], - dst->snscb_hardaddr[i]); + ISP_IOXGET_8(isp, &src->snscb_hardaddr[i], dst->snscb_hardaddr[i]); } } @@ -1333,8 +1845,7 @@ isp_get_els(ispsoftc_t *isp, els_t *src, els_t *dst) ISP_IOXGET_32(isp, &src->els_subcode1, dst->els_subcode1); ISP_IOXGET_32(isp, &src->els_subcode2, dst->els_subcode2); for (i = 0; i < 20; i++) { - ISP_IOXGET_8(isp, &src->els_reserved4[i], - dst->els_reserved4[i]); + ISP_IOXGET_8(isp, &src->els_reserved4[i], dst->els_reserved4[i]); } } @@ -1388,19 +1899,14 @@ isp_get_fc_hdr(ispsoftc_t *isp, fc_hdr_t *src, fc_hdr_t *dst) ISP_IOZGET_8(isp, &src->s_id[1], dst->s_id[1]); ISP_IOZGET_8(isp, &src->s_id[2], dst->s_id[2]); ISP_IOZGET_8(isp, &src->type, dst->type); - ISP_IOZGET_8(isp, &src->f_ctl, dst->f_ctl); + ISP_IOZGET_8(isp, &src->f_ctl[0], dst->f_ctl[0]); + ISP_IOZGET_8(isp, &src->f_ctl[1], dst->f_ctl[1]); + ISP_IOZGET_8(isp, &src->f_ctl[2], dst->f_ctl[2]); ISP_IOZGET_8(isp, &src->seq_id, dst->seq_id); ISP_IOZGET_8(isp, &src->df_ctl, dst->df_ctl); ISP_IOZGET_16(isp, &src->seq_cnt, dst->seq_cnt); - /* XXX SOMETHING WAS AND STILL CONTINUES WRONG HERE XXX */ -#if 0 ISP_IOZGET_16(isp, &src->ox_id, dst->ox_id); ISP_IOZGET_16(isp, &src->rx_id, dst->rx_id); -#else - ISP_IOZGET_32(isp, &src->ox_id, dst->parameter); - dst->ox_id = dst->parameter; - dst->rx_id = dst->parameter >> 16; -#endif ISP_IOZGET_32(isp, &src->parameter, dst->parameter); } @@ -1413,18 +1919,13 @@ isp_get_fcp_cmnd_iu(ispsoftc_t *isp, fcp_cmnd_iu_t *src, fcp_cmnd_iu_t *dst) ISP_IOZGET_8(isp, &src->fcp_cmnd_lun[i], dst->fcp_cmnd_lun[i]); } ISP_IOZGET_8(isp, &src->fcp_cmnd_crn, dst->fcp_cmnd_crn); - ISP_IOZGET_8(isp, &src->fcp_cmnd_task_attribute, - dst->fcp_cmnd_task_attribute); - ISP_IOZGET_8(isp, &src->fcp_cmnd_task_management, - dst->fcp_cmnd_task_management); - ISP_IOZGET_8(isp, &src->fcp_cmnd_alen_datadir, - dst->fcp_cmnd_alen_datadir); + ISP_IOZGET_8(isp, &src->fcp_cmnd_task_attribute, dst->fcp_cmnd_task_attribute); + ISP_IOZGET_8(isp, &src->fcp_cmnd_task_management, dst->fcp_cmnd_task_management); + ISP_IOZGET_8(isp, &src->fcp_cmnd_alen_datadir, dst->fcp_cmnd_alen_datadir); for (i = 0; i < 16; i++) { - ISP_IOZGET_8(isp, &src->cdb_dl.sf.fcp_cmnd_cdb[i], - dst->cdb_dl.sf.fcp_cmnd_cdb[i]); + ISP_IOZGET_8(isp, &src->cdb_dl.sf.fcp_cmnd_cdb[i], dst->cdb_dl.sf.fcp_cmnd_cdb[i]); } - ISP_IOZGET_32(isp, &src->cdb_dl.sf.fcp_cmnd_dl, - dst->cdb_dl.sf.fcp_cmnd_dl); + ISP_IOZGET_32(isp, &src->cdb_dl.sf.fcp_cmnd_dl, dst->cdb_dl.sf.fcp_cmnd_dl); } void @@ -1437,8 +1938,7 @@ isp_put_rft_id(ispsoftc_t *isp, rft_id_t *src, rft_id_t *dst) ISP_IOZPUT_8(isp, src->rftid_portid[i], &dst->rftid_portid[i]); } for (i = 0; i < 8; i++) { - ISP_IOZPUT_32(isp, src->rftid_fc4types[i], - &dst->rftid_fc4types[i]); + ISP_IOZPUT_32(isp, src->rftid_fc4types[i], &dst->rftid_fc4types[i]); } } @@ -1481,6 +1981,253 @@ isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *src, ct_hdr_t *dst) } #ifdef ISP_TARGET_MODE + +/* + * Command shipping- finish off first queue entry and do dma mapping and + * additional segments as needed. + * + * Called with the first queue entry at least partially filled out. + */ +int +isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir, void *snsptr, uint32_t snslen) +{ + uint8_t storage[QENTRY_LEN], storage2[QENTRY_LEN]; + uint8_t type, nqe; + uint32_t seg, curseg, seglim, nxt, nxtnxt; + ispds_t *dsp = NULL; + ispds64_t *dsp64 = NULL; + void *qe0, *qe1, *sqe = NULL; + + qe0 = isp_getrqentry(isp); + if (qe0 == NULL) { + return (CMD_EAGAIN); + } + nxt = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); + + type = ((isphdr_t *)fqe)->rqs_entry_type; + nqe = 1; + seglim = 0; + + /* + * If we have no data to transmit, just copy the first IOCB and start it up. + */ + if (ddir != ISP_NOXFR) { + /* + * First, figure out how many pieces of data to transfer and what kind and how many we can put into the first queue entry. + */ + switch (type) { + case RQSTYPE_CTIO: + dsp = ((ct_entry_t *)fqe)->ct_dataseg; + seglim = ISP_RQDSEG; + break; + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO3: + { + ct2_entry_t *ct = fqe, *ct2 = (ct2_entry_t *) storage2; + uint16_t swd = ct->rsp.m0.ct_scsi_status & 0xff; + + if ((ct->ct_flags & CT2_SENDSTATUS) && (swd || ct->ct_resid)) { + memcpy(ct2, ct, QENTRY_LEN); + /* + * Clear fields from first CTIO2 that now need to be cleared + */ + ct->ct_header.rqs_seqno = 0; + ct->ct_flags &= ~(CT2_SENDSTATUS|CT2_CCINCR|CT2_FASTPOST); + ct->ct_resid = 0; + ct->ct_syshandle = 0; + ct->rsp.m0.ct_scsi_status = 0; + + /* + * Reset fields in the second CTIO2 as appropriate. + */ + ct2->ct_flags &= ~(CT2_FLAG_MMASK|CT2_DATAMASK|CT2_FASTPOST); + ct2->ct_flags |= CT2_NO_DATA|CT2_FLAG_MODE1; + ct2->ct_seg_count = 0; + ct2->ct_reloff = 0; + memset(&ct2->rsp, 0, sizeof (ct2->rsp)); + if (swd == SCSI_CHECK && snsptr && snslen) { + ct2->rsp.m1.ct_senselen = min(snslen, MAXRESPLEN); + memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_senselen); + swd |= CT2_SNSLEN_VALID; + } + if (ct2->ct_resid > 0) { + swd |= CT2_DATA_UNDER; + } else if (ct2->ct_resid < 0) { + swd |= CT2_DATA_OVER; + } + ct2->rsp.m1.ct_scsi_status = swd; + sqe = storage2; + } + if (type == RQSTYPE_CTIO2) { + dsp = ct->rsp.m0.u.ct_dataseg; + seglim = ISP_RQDSEG_T2; + } else { + dsp64 = ct->rsp.m0.u.ct_dataseg64; + seglim = ISP_RQDSEG_T3; + } + break; + } + case RQSTYPE_CTIO7: + { + ct7_entry_t *ct = fqe, *ct2 = (ct7_entry_t *)storage2; + uint16_t swd = ct->ct_scsi_status & 0xff; + + dsp64 = &ct->rsp.m0.ds; + seglim = 1; + if ((ct->ct_flags & CT7_SENDSTATUS) && (swd || ct->ct_resid)) { + memcpy(ct2, ct, sizeof (ct7_entry_t)); + + /* + * Clear fields from first CTIO7 that now need to be cleared + */ + ct->ct_header.rqs_seqno = 0; + ct->ct_flags &= ~CT7_SENDSTATUS; + ct->ct_resid = 0; + ct->ct_syshandle = 0; + ct->ct_scsi_status = 0; + + /* + * Reset fields in the second CTIO7 as appropriate. + */ + ct2->ct_flags &= ~(CT7_FLAG_MMASK|CT7_DATAMASK); + ct2->ct_flags |= CT7_NO_DATA|CT7_NO_DATA|CT7_FLAG_MODE1; + ct2->ct_seg_count = 0; + memset(&ct2->rsp, 0, sizeof (ct2->rsp)); + if (swd == SCSI_CHECK && snsptr && snslen) { + ct2->rsp.m1.ct_resplen = min(snslen, MAXRESPLEN_24XX); + memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_resplen); + swd |= (FCP_SNSLEN_VALID << 8); + } + if (ct2->ct_resid < 0) { + swd |= (FCP_RESID_OVERFLOW << 8); + } else if (ct2->ct_resid > 0) { + swd |= (FCP_RESID_UNDERFLOW << 8); + } + ct2->ct_scsi_status = swd; + sqe = storage2; + } + break; + } + default: + return (CMD_COMPLETE); + } + } + + /* + * Fill out the data transfer stuff in the first queue entry + */ + if (seglim > nsegs) { + seglim = nsegs; + } + + for (seg = curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + + /* + * First, if we are sending status with data and we have a non-zero + * status or non-zero residual, we have to make a synthetic extra CTIO + * that contains the status that we'll ship separately (FC cards only). + */ + + /* + * Second, start building additional continuation segments as needed. + */ + while (seg < nsegs) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + ISP_MEMZERO(storage, QENTRY_LEN); + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (dsp64) { + ispcontreq64_t *crq = (ispcontreq64_t *) storage; + seglim = ISP_CDSEG64; + crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; + crq->req_header.rqs_entry_count = 1; + dsp64 = crq->req_dataseg; + } else { + ispcontreq_t *crq = (ispcontreq_t *) storage; + seglim = ISP_CDSEG; + crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; + crq->req_header.rqs_entry_count = 1; + dsp = crq->req_dataseg; + } + if (seg + seglim > nsegs) { + seglim = nsegs - seg; + } + for (curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + if (dsp64) { + isp_put_cont64_req(isp, (ispcontreq64_t *)storage, qe1); + } else { + isp_put_cont_req(isp, (ispcontreq_t *)storage, qe1); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "additional queue entry", QENTRY_LEN, storage); + } + nqe++; + } + + /* + * If we have a synthetic queue entry to complete things, do it here. + */ + if (sqe) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (type == RQSTYPE_CTIO7) { + isp_put_ctio7(isp, sqe, qe1); + } else { + isp_put_ctio2(isp, sqe, qe1); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "synthetic final queue entry", QENTRY_LEN, storage2); + } + } + + ((isphdr_t *)fqe)->rqs_entry_count = nqe; + switch (type) { + case RQSTYPE_CTIO: + ((ct_entry_t *)fqe)->ct_seg_count = nsegs; + isp_put_ctio(isp, fqe, qe0); + break; + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO3: + ((ct2_entry_t *)fqe)->ct_seg_count = nsegs; + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_ctio2e(isp, fqe, qe0); + } else { + isp_put_ctio2(isp, fqe, qe0); + } + break; + case RQSTYPE_CTIO7: + ((ct7_entry_t *)fqe)->ct_seg_count = nsegs; + isp_put_ctio7(isp, fqe, qe0); + break; + default: + return (CMD_COMPLETE); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "first queue entry", QENTRY_LEN, fqe); + } + ISP_ADD_REQUEST(isp, nxt); + return (CMD_QUEUED); +} + int isp_save_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep) { @@ -1502,9 +2249,8 @@ isp_save_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep) void * isp_find_xs_tgt(ispsoftc_t *isp, uint32_t handle) { - if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || - (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) { - isp_prt(isp, ISP_LOGERR, "bad handle in isp_find_xs_tgt"); + if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) { + isp_prt(isp, ISP_LOGERR, "bad handle %u in isp_find_xs_tgt", handle); return (NULL); } else { return (isp->isp_tgtlist[(handle & ISP_HANDLE_MASK) - 1]); @@ -1518,7 +2264,11 @@ isp_find_tgt_handle(ispsoftc_t *isp, void *xs) if (xs != NULL) { for (i = 0; i < isp->isp_maxcmds; i++) { if (isp->isp_tgtlist[i] == xs) { - return ((i+1) & ISP_HANDLE_MASK); + uint32_t handle = i; + handle += 1; + handle &= ISP_HANDLE_MASK; + handle |= 0x8000; + return (handle); } } } @@ -1528,15 +2278,358 @@ isp_find_tgt_handle(ispsoftc_t *isp, void *xs) void isp_destroy_tgt_handle(ispsoftc_t *isp, uint32_t handle) { - if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || - (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) { - isp_prt(isp, ISP_LOGERR, - "bad handle in isp_destroy_tgt_handle"); + if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) { + isp_prt(isp, ISP_LOGERR, "bad handle in isp_destroy_tgt_handle"); } else { isp->isp_tgtlist[(handle & ISP_HANDLE_MASK) - 1] = NULL; } } +/* + * Find target mode entries + */ +int +isp_find_pdb_by_wwn(ispsoftc_t *isp, int chan, uint64_t wwn, fcportdb_t **lptr) +{ + fcparam *fcp; + int i; + + if (chan < isp->isp_nchan) { + fcp = FCPARAM(isp, chan); + for (i = 0; i < MAX_FC_TARG; i++) { + fcportdb_t *lp = &fcp->portdb[i]; + + if (lp->target_mode == 0) { + continue; + } + if (lp->port_wwn == wwn) { + *lptr = lp; + return (1); + } + } + } + return (0); +} + +int +isp_find_pdb_by_loopid(ispsoftc_t *isp, int chan, uint32_t loopid, fcportdb_t **lptr) +{ + fcparam *fcp; + int i; + + if (chan < isp->isp_nchan) { + fcp = FCPARAM(isp, chan); + for (i = 0; i < MAX_FC_TARG; i++) { + fcportdb_t *lp = &fcp->portdb[i]; + + if (lp->target_mode == 0) { + continue; + } + if (lp->handle == loopid) { + *lptr = lp; + return (1); + } + } + } + return (0); +} + +int +isp_find_pdb_by_sid(ispsoftc_t *isp, int chan, uint32_t sid, fcportdb_t **lptr) +{ + fcparam *fcp; + int i; + + if (chan >= isp->isp_nchan) { + return (0); + } + + fcp = FCPARAM(isp, chan); + for (i = 0; i < MAX_FC_TARG; i++) { + fcportdb_t *lp = &fcp->portdb[i]; + + if (lp->target_mode == 0) { + continue; + } + if (lp->portid == sid) { + *lptr = lp; + return (1); + } + } + return (0); +} + +void +isp_find_chan_by_did(ispsoftc_t *isp, uint32_t did, uint16_t *cp) +{ + uint16_t chan; + + *cp = ISP_NOCHAN; + for (chan = 0; chan < isp->isp_nchan; chan++) { + fcparam *fcp = FCPARAM(isp, chan); + if ((fcp->role & ISP_ROLE_TARGET) == 0 || fcp->isp_fwstate != FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) { + continue; + } + if (fcp->isp_portid == did) { + *cp = chan; + break; + } + } +} + +/* + * Add an initiator device to the port database + */ +void +isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint32_t s_id) +{ + fcparam *fcp; + fcportdb_t *lp; + isp_notify_t nt; + int i; + + fcp = FCPARAM(isp, chan); + + if (nphdl >= MAX_NPORT_HANDLE) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x", + __func__, chan, (unsigned long long) ini, nphdl, s_id); + return; + } + + lp = NULL; + if (fcp->isp_tgt_map[nphdl]) { + lp = &fcp->portdb[fcp->isp_tgt_map[nphdl] - 1]; + } else { + /* + * Make sure the addition of a new target mode entry doesn't duplicate entries + * with the same N-Port handles, the same portids or the same Port WWN. + */ + for (i = 0; i < MAX_FC_TARG; i++) { + lp = &fcp->portdb[i]; + if (lp->target_mode == 0) { + lp = NULL; + continue; + } + if (lp->handle == nphdl) { + break; + } + if (s_id != PORT_ANY && lp->portid == s_id) { + break; + } + if (VALID_INI(ini) && lp->port_wwn == ini) { + break; + } + lp = NULL; + } + + } + + if (lp) { + int something = 0; + if (lp->handle != nphdl) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d attempt to re-enter N-port handle 0x%04x IID 0x%016llx Port ID 0x%06x finds IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x", + __func__, chan, nphdl, (unsigned long long)ini, s_id, (unsigned long long) lp->port_wwn, lp->handle, lp->portid); + isp_dump_portdb(isp, chan); + return; + } + if (s_id != PORT_NONE) { + if (lp->portid == PORT_NONE) { + lp->portid = s_id; + isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x gets Port ID 0x%06x", __func__, chan, nphdl, s_id); + something++; + } else if (lp->portid != s_id) { + isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x tries to change Port ID 0x%06x to 0x%06x", __func__, chan, nphdl, + lp->portid, s_id); + isp_dump_portdb(isp, chan); + return; + } + } + if (VALID_INI(ini)) { + if (!VALID_INI(lp->port_wwn)) { + lp->port_wwn = ini; + isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x gets WWN 0x%016llxx", __func__, chan, nphdl, (unsigned long long) ini); + something++; + } else if (lp->port_wwn != ini) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d N-port handle 0x%04x tries to change WWN 0x%016llx to 0x%016llx", __func__, chan, nphdl, + (unsigned long long) lp->port_wwn, (unsigned long long) ini); + isp_dump_portdb(isp, chan); + return; + } + } + + if (!something) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x reentered", __func__, chan, + (unsigned long long) lp->port_wwn, lp->handle, lp->portid); + } + return; + } + + /* + * Find a new spot + */ + for (i = MAX_FC_TARG - 1; i >= 0; i--) { + if (fcp->portdb[i].target_mode == 1) { + continue; + } + if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { + break; + } + } + if (i < 0) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x- no room in port database", + __func__, chan, (unsigned long long) ini, nphdl, s_id); + return; + } + + lp = &fcp->portdb[i]; + ISP_MEMZERO(lp, sizeof (fcportdb_t)); + lp->target_mode = 1; + lp->handle = nphdl; + lp->portid = s_id; + lp->port_wwn = ini; + fcp->isp_tgt_map[nphdl] = i + 1; + + isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d added", __func__, chan, (unsigned long long) ini, nphdl, s_id, fcp->isp_tgt_map[nphdl] - 1); + + ISP_MEMZERO(&nt, sizeof (nt)); + nt.nt_hba = isp; + nt.nt_wwn = ini; + nt.nt_tgt = FCPARAM(isp, chan)->isp_wwpn; + nt.nt_sid = s_id; + nt.nt_did = FCPARAM(isp, chan)->isp_portid; + nt.nt_nphdl = nphdl; + nt.nt_channel = chan; + nt.nt_ncode = NT_ARRIVED; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); +} + +/* + * Remove a target device to the port database + */ +void +isp_del_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint32_t s_id) +{ + fcparam *fcp; + isp_notify_t nt; + fcportdb_t *lp; + + if (nphdl >= MAX_NPORT_HANDLE) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x", + __func__, chan, (unsigned long long) ini, nphdl, s_id); + return; + } + + fcp = FCPARAM(isp, chan); + if (fcp->isp_tgt_map[nphdl] == 0) { + lp = NULL; + } else { + lp = &fcp->portdb[fcp->isp_tgt_map[nphdl] - 1]; + if (lp->target_mode == 0) { + lp = NULL; + } + } + if (lp == NULL) { + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be cleared", + __func__, chan, (unsigned long long) ini, nphdl, s_id); + isp_dump_portdb(isp, chan); + return; + } + isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d cleared", + __func__, chan, (unsigned long long) lp->port_wwn, nphdl, lp->portid, fcp->isp_tgt_map[nphdl] - 1); + fcp->isp_tgt_map[nphdl] = 0; + + ISP_MEMZERO(&nt, sizeof (nt)); + nt.nt_hba = isp; + nt.nt_wwn = lp->port_wwn; + nt.nt_tgt = FCPARAM(isp, chan)->isp_wwpn; + nt.nt_sid = lp->portid; + nt.nt_did = FCPARAM(isp, chan)->isp_portid; + nt.nt_nphdl = nphdl; + nt.nt_channel = chan; + nt.nt_ncode = NT_DEPARTED; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); +} + +void +isp_del_all_wwn_entries(ispsoftc_t *isp, int chan) +{ + fcparam *fcp; + int i; + + if (!IS_FC(isp)) { + return; + } + + /* + * Handle iterations over all channels via recursion + */ + if (chan == ISP_NOCHAN) { + for (chan = 0; chan < isp->isp_nchan; chan++) { + isp_del_all_wwn_entries(isp, chan); + } + return; + } + + if (chan > isp->isp_nchan) { + return; + } + + fcp = FCPARAM(isp, chan); + if (fcp == NULL) { + return; + } + for (i = 0; i < MAX_NPORT_HANDLE; i++) { + if (fcp->isp_tgt_map[i]) { + fcportdb_t *lp = &fcp->portdb[fcp->isp_tgt_map[i] - 1]; + isp_del_wwn_entry(isp, chan, lp->port_wwn, lp->handle, lp->portid); + } + } +} + +void +isp_del_wwn_entries(ispsoftc_t *isp, isp_notify_t *mp) +{ + fcportdb_t *lp; + + /* + * Handle iterations over all channels via recursion + */ + if (mp->nt_channel == ISP_NOCHAN) { + for (mp->nt_channel = 0; mp->nt_channel < isp->isp_nchan; mp->nt_channel++) { + isp_del_wwn_entries(isp, mp); + } + mp->nt_channel = ISP_NOCHAN; + return; + } + + /* + * We have an entry which is only partially identified. + * + * It's only known by WWN, N-Port handle, or Port ID. + * We need to find the actual entry so we can delete it. + */ + if (mp->nt_nphdl != NIL_HANDLE) { + if (isp_find_pdb_by_loopid(isp, mp->nt_channel, mp->nt_nphdl, &lp)) { + isp_del_wwn_entry(isp, mp->nt_channel, lp->port_wwn, lp->handle, lp->portid); + return; + } + } + if (mp->nt_wwn != INI_ANY) { + if (isp_find_pdb_by_wwn(isp, mp->nt_channel, mp->nt_wwn, &lp)) { + isp_del_wwn_entry(isp, mp->nt_channel, lp->port_wwn, lp->handle, lp->portid); + return; + } + } + if (mp->nt_sid != PORT_ANY && mp->nt_sid != PORT_NONE) { + if (isp_find_pdb_by_sid(isp, mp->nt_channel, mp->nt_sid, &lp)) { + isp_del_wwn_entry(isp, mp->nt_channel, lp->port_wwn, lp->handle, lp->portid); + return; + } + } + isp_prt(isp, ISP_LOGWARN, "%s: Chan %d unable to find entry to delete N-port handle 0x%04x initiator WWN 0x%016llx Port ID 0x%06x", __func__, + mp->nt_channel, mp->nt_nphdl, (unsigned long long) mp->nt_wwn, mp->nt_sid); +} + void isp_put_atio(ispsoftc_t *isp, at_entry_t *src, at_entry_t *dst) { @@ -1559,8 +2652,7 @@ isp_put_atio(ispsoftc_t *isp, at_entry_t *src, at_entry_t *dst) ISP_IOXPUT_8(isp, src->at_cdblen, &dst->at_cdblen); ISP_IOXPUT_8(isp, src->at_tgt, &dst->at_tgt); ISP_IOXPUT_8(isp, src->at_status, &dst->at_status); - ISP_IOXPUT_8(isp, src->at_scsi_status, - &dst->at_scsi_status); + ISP_IOXPUT_8(isp, src->at_scsi_status, &dst->at_scsi_status); ISP_IOXPUT_8(isp, src->at_tag_val, &dst->at_tag_val); ISP_IOXPUT_8(isp, src->at_tag_type, &dst->at_tag_type); } @@ -1595,8 +2687,7 @@ isp_get_atio(ispsoftc_t *isp, at_entry_t *src, at_entry_t *dst) ISP_IOXGET_8(isp, &src->at_cdblen, dst->at_cdblen); ISP_IOXGET_8(isp, &src->at_tgt, dst->at_tgt); ISP_IOXGET_8(isp, &src->at_status, dst->at_status); - ISP_IOXGET_8(isp, &src->at_scsi_status, - dst->at_scsi_status); + ISP_IOXGET_8(isp, &src->at_scsi_status, dst->at_scsi_status); ISP_IOXGET_8(isp, &src->at_tag_val, dst->at_tag_val); ISP_IOXGET_8(isp, &src->at_tag_type, dst->at_tag_type); } @@ -1633,8 +2724,7 @@ isp_put_atio2(ispsoftc_t *isp, at2_entry_t *src, at2_entry_t *dst) ISP_IOXPUT_16(isp, src->at_wwpn[i], &dst->at_wwpn[i]); } for (i = 0; i < 6; i++) { - ISP_IOXPUT_16(isp, src->at_reserved2[i], - &dst->at_reserved2[i]); + ISP_IOXPUT_16(isp, src->at_reserved2[i], &dst->at_reserved2[i]); } ISP_IOXPUT_16(isp, src->at_oxid, &dst->at_oxid); } @@ -1662,8 +2752,7 @@ isp_put_atio2e(ispsoftc_t *isp, at2e_entry_t *src, at2e_entry_t *dst) ISP_IOXPUT_16(isp, src->at_wwpn[i], &dst->at_wwpn[i]); } for (i = 0; i < 6; i++) { - ISP_IOXPUT_16(isp, src->at_reserved2[i], - &dst->at_reserved2[i]); + ISP_IOXPUT_16(isp, src->at_reserved2[i], &dst->at_reserved2[i]); } ISP_IOXPUT_16(isp, src->at_oxid, &dst->at_oxid); } @@ -1692,8 +2781,7 @@ isp_get_atio2(ispsoftc_t *isp, at2_entry_t *src, at2_entry_t *dst) ISP_IOXGET_16(isp, &src->at_wwpn[i], dst->at_wwpn[i]); } for (i = 0; i < 6; i++) { - ISP_IOXGET_16(isp, &src->at_reserved2[i], - dst->at_reserved2[i]); + ISP_IOXGET_16(isp, &src->at_reserved2[i], dst->at_reserved2[i]); } ISP_IOXGET_16(isp, &src->at_oxid, dst->at_oxid); } @@ -1721,8 +2809,7 @@ isp_get_atio2e(ispsoftc_t *isp, at2e_entry_t *src, at2e_entry_t *dst) ISP_IOXGET_16(isp, &src->at_wwpn[i], dst->at_wwpn[i]); } for (i = 0; i < 6; i++) { - ISP_IOXGET_16(isp, &src->at_reserved2[i], - dst->at_reserved2[i]); + ISP_IOXGET_16(isp, &src->at_reserved2[i], dst->at_reserved2[i]); } ISP_IOXGET_16(isp, &src->at_oxid, dst->at_oxid); } @@ -1771,10 +2858,8 @@ isp_put_ctio(ispsoftc_t *isp, ct_entry_t *src, ct_entry_t *dst) ISP_IOXPUT_16(isp, src->ct_timeout, &dst->ct_timeout); ISP_IOXPUT_16(isp, src->ct_seg_count, &dst->ct_seg_count); for (i = 0; i < ISP_RQDSEG; i++) { - ISP_IOXPUT_32(isp, src->ct_dataseg[i].ds_base, - &dst->ct_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, src->ct_dataseg[i].ds_count, - &dst->ct_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->ct_dataseg[i].ds_base, &dst->ct_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->ct_dataseg[i].ds_count, &dst->ct_dataseg[i].ds_count); } } @@ -1800,8 +2885,7 @@ isp_get_ctio(ispsoftc_t *isp, ct_entry_t *src, ct_entry_t *dst) ISP_IOXGET_8(isp, &src->ct_reserved2, dst->ct_reserved2); ISP_IOXGET_8(isp, &src->ct_tgt, dst->ct_tgt); ISP_IOXGET_8(isp, &src->ct_status, dst->ct_status); - ISP_IOXGET_8(isp, &src->ct_scsi_status, - dst->ct_scsi_status); + ISP_IOXGET_8(isp, &src->ct_scsi_status, dst->ct_scsi_status); ISP_IOXGET_8(isp, &src->ct_tag_val, dst->ct_tag_val); ISP_IOXGET_8(isp, &src->ct_tag_type, dst->ct_tag_type); } @@ -1811,12 +2895,8 @@ isp_get_ctio(ispsoftc_t *isp, ct_entry_t *src, ct_entry_t *dst) ISP_IOXGET_16(isp, &src->ct_timeout, dst->ct_timeout); ISP_IOXGET_16(isp, &src->ct_seg_count, dst->ct_seg_count); for (i = 0; i < ISP_RQDSEG; i++) { - ISP_IOXGET_32(isp, - &src->ct_dataseg[i].ds_base, - dst->ct_dataseg[i].ds_base); - ISP_IOXGET_32(isp, - &src->ct_dataseg[i].ds_count, - dst->ct_dataseg[i].ds_count); + ISP_IOXGET_32(isp, &src->ct_dataseg[i].ds_base, dst->ct_dataseg[i].ds_base); + ISP_IOXGET_32(isp, &src->ct_dataseg[i].ds_count, dst->ct_dataseg[i].ds_count); } } @@ -1835,71 +2915,42 @@ isp_put_ctio2(ispsoftc_t *isp, ct2_entry_t *src, ct2_entry_t *dst) ISP_IOXPUT_32(isp, src->ct_resid, &dst->ct_resid); ISP_IOXPUT_32(isp, src->ct_reloff, &dst->ct_reloff); if ((src->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE0) { - ISP_IOXPUT_32(isp, src->rsp.m0._reserved, - &dst->rsp.m0._reserved); - ISP_IOXPUT_16(isp, src->rsp.m0._reserved2, - &dst->rsp.m0._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m0.ct_scsi_status, - &dst->rsp.m0.ct_scsi_status); - ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, - &dst->rsp.m0.ct_xfrlen); + ISP_IOXPUT_32(isp, src->rsp.m0._reserved, &dst->rsp.m0._reserved); + ISP_IOXPUT_16(isp, src->rsp.m0._reserved2, &dst->rsp.m0._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m0.ct_scsi_status, &dst->rsp.m0.ct_scsi_status); + ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, &dst->rsp.m0.ct_xfrlen); if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) { for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg[i].ds_base, - &dst->rsp.m0.u.ct_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg[i].ds_count, - &dst->rsp.m0.u.ct_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg[i].ds_base, &dst->rsp.m0.u.ct_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg[i].ds_count, &dst->rsp.m0.u.ct_dataseg[i].ds_count); } } else if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_base, - &dst->rsp.m0.u.ct_dataseg64[i].ds_base); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_basehi, - &dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_count, - &dst->rsp.m0.u.ct_dataseg64[i].ds_count); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_base, &dst->rsp.m0.u.ct_dataseg64[i].ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_basehi, &dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_count, &dst->rsp.m0.u.ct_dataseg64[i].ds_count); } } else if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO4) { - ISP_IOXPUT_16(isp, src->rsp.m0.u.ct_dslist.ds_type, - &dst->rsp.m0.u.ct_dslist.ds_type); - ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_segment, + ISP_IOXPUT_16(isp, src->rsp.m0.u.ct_dslist.ds_type, &dst->rsp.m0.u.ct_dslist.ds_type); ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_segment, &dst->rsp.m0.u.ct_dslist.ds_segment); - ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_base, - &dst->rsp.m0.u.ct_dslist.ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_base, &dst->rsp.m0.u.ct_dslist.ds_base); } } else if ((src->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE1) { - ISP_IOXPUT_16(isp, src->rsp.m1._reserved, - &dst->rsp.m1._reserved); - ISP_IOXPUT_16(isp, src->rsp.m1._reserved2, - &dst->rsp.m1._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_senselen, - &dst->rsp.m1.ct_senselen); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_scsi_status, - &dst->rsp.m1.ct_scsi_status); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, - &dst->rsp.m1.ct_resplen); + ISP_IOXPUT_16(isp, src->rsp.m1._reserved, &dst->rsp.m1._reserved); + ISP_IOXPUT_16(isp, src->rsp.m1._reserved2, &dst->rsp.m1._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_senselen, &dst->rsp.m1.ct_senselen); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_scsi_status, &dst->rsp.m1.ct_scsi_status); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, &dst->rsp.m1.ct_resplen); for (i = 0; i < MAXRESPLEN; i++) { - ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i], - &dst->rsp.m1.ct_resp[i]); + ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i], &dst->rsp.m1.ct_resp[i]); } } else { - ISP_IOXPUT_32(isp, src->rsp.m2._reserved, - &dst->rsp.m2._reserved); - ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, - &dst->rsp.m2._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, - &dst->rsp.m2._reserved3); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, - &dst->rsp.m2.ct_datalen); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXPUT_32(isp, src->rsp.m2._reserved, &dst->rsp.m2._reserved); + ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, &dst->rsp.m2._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, &dst->rsp.m2._reserved3); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -1917,71 +2968,42 @@ isp_put_ctio2e(ispsoftc_t *isp, ct2e_entry_t *src, ct2e_entry_t *dst) ISP_IOXPUT_32(isp, src->ct_resid, &dst->ct_resid); ISP_IOXPUT_32(isp, src->ct_reloff, &dst->ct_reloff); if ((src->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE0) { - ISP_IOXPUT_32(isp, src->rsp.m0._reserved, - &dst->rsp.m0._reserved); - ISP_IOXPUT_16(isp, src->rsp.m0._reserved2, - &dst->rsp.m0._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m0.ct_scsi_status, - &dst->rsp.m0.ct_scsi_status); - ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, - &dst->rsp.m0.ct_xfrlen); + ISP_IOXPUT_32(isp, src->rsp.m0._reserved, &dst->rsp.m0._reserved); + ISP_IOXPUT_16(isp, src->rsp.m0._reserved2, &dst->rsp.m0._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m0.ct_scsi_status, &dst->rsp.m0.ct_scsi_status); + ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, &dst->rsp.m0.ct_xfrlen); if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) { for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg[i].ds_base, - &dst->rsp.m0.u.ct_dataseg[i].ds_base); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg[i].ds_count, - &dst->rsp.m0.u.ct_dataseg[i].ds_count); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg[i].ds_base, &dst->rsp.m0.u.ct_dataseg[i].ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg[i].ds_count, &dst->rsp.m0.u.ct_dataseg[i].ds_count); } } else if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_base, - &dst->rsp.m0.u.ct_dataseg64[i].ds_base); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_basehi, - &dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); - ISP_IOXPUT_32(isp, - src->rsp.m0.u.ct_dataseg64[i].ds_count, - &dst->rsp.m0.u.ct_dataseg64[i].ds_count); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_base, &dst->rsp.m0.u.ct_dataseg64[i].ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_basehi, &dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dataseg64[i].ds_count, &dst->rsp.m0.u.ct_dataseg64[i].ds_count); } } else if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO4) { - ISP_IOXPUT_16(isp, src->rsp.m0.u.ct_dslist.ds_type, - &dst->rsp.m0.u.ct_dslist.ds_type); - ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_segment, - &dst->rsp.m0.u.ct_dslist.ds_segment); - ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_base, - &dst->rsp.m0.u.ct_dslist.ds_base); + ISP_IOXPUT_16(isp, src->rsp.m0.u.ct_dslist.ds_type, &dst->rsp.m0.u.ct_dslist.ds_type); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_segment, &dst->rsp.m0.u.ct_dslist.ds_segment); + ISP_IOXPUT_32(isp, src->rsp.m0.u.ct_dslist.ds_base, &dst->rsp.m0.u.ct_dslist.ds_base); } } else if ((src->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE1) { - ISP_IOXPUT_16(isp, src->rsp.m1._reserved, - &dst->rsp.m1._reserved); - ISP_IOXPUT_16(isp, src->rsp.m1._reserved2, - &dst->rsp.m1._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_senselen, - &dst->rsp.m1.ct_senselen); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_scsi_status, - &dst->rsp.m1.ct_scsi_status); - ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, - &dst->rsp.m1.ct_resplen); + ISP_IOXPUT_16(isp, src->rsp.m1._reserved, &dst->rsp.m1._reserved); + ISP_IOXPUT_16(isp, src->rsp.m1._reserved2, &dst->rsp.m1._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_senselen, &dst->rsp.m1.ct_senselen); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_scsi_status, &dst->rsp.m1.ct_scsi_status); + ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, &dst->rsp.m1.ct_resplen); for (i = 0; i < MAXRESPLEN; i++) { - ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i], - &dst->rsp.m1.ct_resp[i]); + ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i], &dst->rsp.m1.ct_resp[i]); } } else { - ISP_IOXPUT_32(isp, src->rsp.m2._reserved, - &dst->rsp.m2._reserved); - ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, - &dst->rsp.m2._reserved2); - ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, - &dst->rsp.m2._reserved3); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, - &dst->rsp.m2.ct_datalen); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXPUT_32(isp, src->rsp.m2._reserved, &dst->rsp.m2._reserved); + ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, &dst->rsp.m2._reserved2); + ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, &dst->rsp.m2._reserved3); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -1995,7 +3017,7 @@ isp_put_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst) ISP_IOXPUT_16(isp, src->ct_nphdl, &dst->ct_nphdl); ISP_IOXPUT_16(isp, src->ct_timeout, &dst->ct_timeout); ISP_IOXPUT_16(isp, src->ct_seg_count, &dst->ct_seg_count); - ISP_IOXPUT_8(isp, src->ct_vpindex, &dst->ct_vpindex); + ISP_IOXPUT_8(isp, src->ct_vpidx, &dst->ct_vpidx); ISP_IOXPUT_8(isp, src->ct_xflags, &dst->ct_xflags); ISP_IOXPUT_16(isp, src->ct_iid_lo, &dst->ct_iid_lo); ISP_IOXPUT_8(isp, src->ct_iid_hi, &dst->ct_iid_hi); @@ -2008,39 +3030,29 @@ isp_put_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst) ISP_IOXPUT_16(isp, src->ct_scsi_status, &dst->ct_scsi_status); if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE0) { ISP_IOXPUT_32(isp, src->rsp.m0.reloff, &dst->rsp.m0.reloff); - ISP_IOXPUT_32(isp, src->rsp.m0.reserved0, - &dst->rsp.m0.reserved0); - ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, - &dst->rsp.m0.ct_xfrlen); - ISP_IOXPUT_32(isp, src->rsp.m0.reserved1, - &dst->rsp.m0.reserved1); - ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_base, - &dst->rsp.m0.ds.ds_base); - ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_basehi, - &dst->rsp.m0.ds.ds_basehi); - ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_count, - &dst->rsp.m0.ds.ds_count); + ISP_IOXPUT_32(isp, src->rsp.m0.reserved0, &dst->rsp.m0.reserved0); + ISP_IOXPUT_32(isp, src->rsp.m0.ct_xfrlen, &dst->rsp.m0.ct_xfrlen); + ISP_IOXPUT_32(isp, src->rsp.m0.reserved1, &dst->rsp.m0.reserved1); + ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_base, &dst->rsp.m0.ds.ds_base); + ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_basehi, &dst->rsp.m0.ds.ds_basehi); + ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_count, &dst->rsp.m0.ds.ds_count); } else if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE1) { - ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, - &dst->rsp.m1.ct_resplen); + uint32_t *a, *b; + + ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen, &dst->rsp.m1.ct_resplen); ISP_IOXPUT_16(isp, src->rsp.m1.reserved, &dst->rsp.m1.reserved); - for (i = 0; i < MAXRESPLEN_24XX; i++) { - ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i], - &dst->rsp.m1.ct_resp[i]); + a = (uint32_t *) src->rsp.m1.ct_resp; + b = (uint32_t *) dst->rsp.m1.ct_resp; + for (i = 0; i < (ASIZE(src->rsp.m1.ct_resp) >> 2); i++) { + *b++ = ISP_SWAP32(isp, *a++); } } else { - ISP_IOXPUT_32(isp, src->rsp.m2.reserved0, - &dst->rsp.m2.reserved0); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, - &dst->rsp.m2.ct_datalen); - ISP_IOXPUT_32(isp, src->rsp.m2.reserved1, - &dst->rsp.m2.reserved1); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_basehi, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_basehi); - ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXPUT_32(isp, src->rsp.m2.reserved0, &dst->rsp.m2.reserved0); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen); + ISP_IOXPUT_32(isp, src->rsp.m2.reserved1, &dst->rsp.m2.reserved1); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_basehi, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_basehi); + ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -2062,71 +3074,42 @@ isp_get_ctio2(ispsoftc_t *isp, ct2_entry_t *src, ct2_entry_t *dst) ISP_IOXGET_32(isp, &src->ct_reloff, dst->ct_reloff); ISP_IOXGET_32(isp, &src->ct_resid, dst->ct_resid); if ((dst->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE0) { - ISP_IOXGET_32(isp, &src->rsp.m0._reserved, - dst->rsp.m0._reserved); - ISP_IOXGET_16(isp, &src->rsp.m0._reserved2, - dst->rsp.m0._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m0.ct_scsi_status, - dst->rsp.m0.ct_scsi_status); - ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, - dst->rsp.m0.ct_xfrlen); + ISP_IOXGET_32(isp, &src->rsp.m0._reserved, dst->rsp.m0._reserved); + ISP_IOXGET_16(isp, &src->rsp.m0._reserved2, dst->rsp.m0._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m0.ct_scsi_status, dst->rsp.m0.ct_scsi_status); + ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, dst->rsp.m0.ct_xfrlen); if (dst->ct_header.rqs_entry_type == RQSTYPE_CTIO2) { for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg[i].ds_base, - dst->rsp.m0.u.ct_dataseg[i].ds_base); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg[i].ds_count, - dst->rsp.m0.u.ct_dataseg[i].ds_count); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg[i].ds_base, dst->rsp.m0.u.ct_dataseg[i].ds_base); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg[i].ds_count, dst->rsp.m0.u.ct_dataseg[i].ds_count); } } else if (dst->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_base, - dst->rsp.m0.u.ct_dataseg64[i].ds_base); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_basehi, - dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_count, - dst->rsp.m0.u.ct_dataseg64[i].ds_count); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_base, dst->rsp.m0.u.ct_dataseg64[i].ds_base); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_basehi, dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_count, dst->rsp.m0.u.ct_dataseg64[i].ds_count); } } else if (dst->ct_header.rqs_entry_type == RQSTYPE_CTIO4) { - ISP_IOXGET_16(isp, &src->rsp.m0.u.ct_dslist.ds_type, - dst->rsp.m0.u.ct_dslist.ds_type); - ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_segment, - dst->rsp.m0.u.ct_dslist.ds_segment); - ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_base, - dst->rsp.m0.u.ct_dslist.ds_base); + ISP_IOXGET_16(isp, &src->rsp.m0.u.ct_dslist.ds_type, dst->rsp.m0.u.ct_dslist.ds_type); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_segment, dst->rsp.m0.u.ct_dslist.ds_segment); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_base, dst->rsp.m0.u.ct_dslist.ds_base); } } else if ((dst->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE1) { - ISP_IOXGET_16(isp, &src->rsp.m1._reserved, - dst->rsp.m1._reserved); - ISP_IOXGET_16(isp, &src->rsp.m1._reserved2, - dst->rsp.m1._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_senselen, - dst->rsp.m1.ct_senselen); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_scsi_status, - dst->rsp.m1.ct_scsi_status); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, - dst->rsp.m1.ct_resplen); + ISP_IOXGET_16(isp, &src->rsp.m1._reserved, dst->rsp.m1._reserved); + ISP_IOXGET_16(isp, &src->rsp.m1._reserved2, dst->rsp.m1._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_senselen, dst->rsp.m1.ct_senselen); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_scsi_status, dst->rsp.m1.ct_scsi_status); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, dst->rsp.m1.ct_resplen); for (i = 0; i < MAXRESPLEN; i++) { - ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], - dst->rsp.m1.ct_resp[i]); + ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], dst->rsp.m1.ct_resp[i]); } } else { - ISP_IOXGET_32(isp, &src->rsp.m2._reserved, - dst->rsp.m2._reserved); - ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, - dst->rsp.m2._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, - dst->rsp.m2._reserved3); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, - dst->rsp.m2.ct_datalen); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXGET_32(isp, &src->rsp.m2._reserved, dst->rsp.m2._reserved); + ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, dst->rsp.m2._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, dst->rsp.m2._reserved3); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, dst->rsp.m2.ct_datalen); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -2146,71 +3129,42 @@ isp_get_ctio2e(ispsoftc_t *isp, ct2e_entry_t *src, ct2e_entry_t *dst) ISP_IOXGET_32(isp, &src->ct_reloff, dst->ct_reloff); ISP_IOXGET_32(isp, &src->ct_resid, dst->ct_resid); if ((dst->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE0) { - ISP_IOXGET_32(isp, &src->rsp.m0._reserved, - dst->rsp.m0._reserved); - ISP_IOXGET_16(isp, &src->rsp.m0._reserved2, - dst->rsp.m0._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m0.ct_scsi_status, - dst->rsp.m0.ct_scsi_status); - ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, - dst->rsp.m0.ct_xfrlen); + ISP_IOXGET_32(isp, &src->rsp.m0._reserved, dst->rsp.m0._reserved); + ISP_IOXGET_16(isp, &src->rsp.m0._reserved2, dst->rsp.m0._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m0.ct_scsi_status, dst->rsp.m0.ct_scsi_status); + ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, dst->rsp.m0.ct_xfrlen); if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) { for (i = 0; i < ISP_RQDSEG_T2; i++) { - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg[i].ds_base, - dst->rsp.m0.u.ct_dataseg[i].ds_base); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg[i].ds_count, - dst->rsp.m0.u.ct_dataseg[i].ds_count); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg[i].ds_base, dst->rsp.m0.u.ct_dataseg[i].ds_base); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg[i].ds_count, dst->rsp.m0.u.ct_dataseg[i].ds_count); } } else if (dst->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { for (i = 0; i < ISP_RQDSEG_T3; i++) { - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_base, - dst->rsp.m0.u.ct_dataseg64[i].ds_base); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_basehi, - dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); - ISP_IOXGET_32(isp, - &src->rsp.m0.u.ct_dataseg64[i].ds_count, - dst->rsp.m0.u.ct_dataseg64[i].ds_count); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_base, dst->rsp.m0.u.ct_dataseg64[i].ds_base); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_basehi, dst->rsp.m0.u.ct_dataseg64[i].ds_basehi); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dataseg64[i].ds_count, dst->rsp.m0.u.ct_dataseg64[i].ds_count); } } else if (dst->ct_header.rqs_entry_type == RQSTYPE_CTIO4) { - ISP_IOXGET_16(isp, &src->rsp.m0.u.ct_dslist.ds_type, - dst->rsp.m0.u.ct_dslist.ds_type); - ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_segment, - dst->rsp.m0.u.ct_dslist.ds_segment); - ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_base, - dst->rsp.m0.u.ct_dslist.ds_base); + ISP_IOXGET_16(isp, &src->rsp.m0.u.ct_dslist.ds_type, dst->rsp.m0.u.ct_dslist.ds_type); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_segment, dst->rsp.m0.u.ct_dslist.ds_segment); + ISP_IOXGET_32(isp, &src->rsp.m0.u.ct_dslist.ds_base, dst->rsp.m0.u.ct_dslist.ds_base); } } else if ((dst->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE1) { - ISP_IOXGET_16(isp, &src->rsp.m1._reserved, - dst->rsp.m1._reserved); - ISP_IOXGET_16(isp, &src->rsp.m1._reserved2, - dst->rsp.m1._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_senselen, - dst->rsp.m1.ct_senselen); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_scsi_status, - dst->rsp.m1.ct_scsi_status); - ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, - dst->rsp.m1.ct_resplen); + ISP_IOXGET_16(isp, &src->rsp.m1._reserved, dst->rsp.m1._reserved); + ISP_IOXGET_16(isp, &src->rsp.m1._reserved2, dst->rsp.m1._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_senselen, dst->rsp.m1.ct_senselen); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_scsi_status, dst->rsp.m1.ct_scsi_status); + ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, dst->rsp.m1.ct_resplen); for (i = 0; i < MAXRESPLEN; i++) { - ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], - dst->rsp.m1.ct_resp[i]); + ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], dst->rsp.m1.ct_resp[i]); } } else { - ISP_IOXGET_32(isp, &src->rsp.m2._reserved, - dst->rsp.m2._reserved); - ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, - dst->rsp.m2._reserved2); - ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, - dst->rsp.m2._reserved3); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, - dst->rsp.m2.ct_datalen); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXGET_32(isp, &src->rsp.m2._reserved, dst->rsp.m2._reserved); + ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, dst->rsp.m2._reserved2); + ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, dst->rsp.m2._reserved3); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, dst->rsp.m2.ct_datalen); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -2224,7 +3178,7 @@ isp_get_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst) ISP_IOXGET_16(isp, &src->ct_nphdl, dst->ct_nphdl); ISP_IOXGET_16(isp, &src->ct_timeout, dst->ct_timeout); ISP_IOXGET_16(isp, &src->ct_seg_count, dst->ct_seg_count); - ISP_IOXGET_8(isp, &src->ct_vpindex, dst->ct_vpindex); + ISP_IOXGET_8(isp, &src->ct_vpidx, dst->ct_vpidx); ISP_IOXGET_8(isp, &src->ct_xflags, dst->ct_xflags); ISP_IOXGET_16(isp, &src->ct_iid_lo, dst->ct_iid_lo); ISP_IOXGET_8(isp, &src->ct_iid_hi, dst->ct_iid_hi); @@ -2237,39 +3191,32 @@ isp_get_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst) ISP_IOXGET_16(isp, &src->ct_scsi_status, dst->ct_scsi_status); if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE0) { ISP_IOXGET_32(isp, &src->rsp.m0.reloff, dst->rsp.m0.reloff); - ISP_IOXGET_32(isp, &src->rsp.m0.reserved0, - dst->rsp.m0.reserved0); - ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, - dst->rsp.m0.ct_xfrlen); - ISP_IOXGET_32(isp, &src->rsp.m0.reserved1, - dst->rsp.m0.reserved1); - ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_base, - dst->rsp.m0.ds.ds_base); - ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_basehi, - dst->rsp.m0.ds.ds_basehi); - ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_count, - dst->rsp.m0.ds.ds_count); + ISP_IOXGET_32(isp, &src->rsp.m0.reserved0, dst->rsp.m0.reserved0); + ISP_IOXGET_32(isp, &src->rsp.m0.ct_xfrlen, dst->rsp.m0.ct_xfrlen); + ISP_IOXGET_32(isp, &src->rsp.m0.reserved1, dst->rsp.m0.reserved1); + ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_base, dst->rsp.m0.ds.ds_base); + ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_basehi, dst->rsp.m0.ds.ds_basehi); + ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_count, dst->rsp.m0.ds.ds_count); } else if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE1) { - ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, - dst->rsp.m1.ct_resplen); + uint32_t *a, *b; + + ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen, dst->rsp.m1.ct_resplen); ISP_IOXGET_16(isp, &src->rsp.m1.reserved, dst->rsp.m1.reserved); + a = (uint32_t *) src->rsp.m1.ct_resp; + b = (uint32_t *) dst->rsp.m1.ct_resp; for (i = 0; i < MAXRESPLEN_24XX; i++) { - ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], - dst->rsp.m1.ct_resp[i]); + ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i], dst->rsp.m1.ct_resp[i]); + } + for (i = 0; i < (ASIZE(src->rsp.m1.ct_resp) >> 2); i++) { + *b++ = ISP_SWAP32(isp, *a++); } } else { - ISP_IOXGET_32(isp, &src->rsp.m2.reserved0, - dst->rsp.m2.reserved0); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, - dst->rsp.m2.ct_datalen); - ISP_IOXGET_32(isp, &src->rsp.m2.reserved1, - dst->rsp.m2.reserved1); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_basehi, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_basehi); - ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, - dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); + ISP_IOXGET_32(isp, &src->rsp.m2.reserved0, dst->rsp.m2.reserved0); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, dst->rsp.m2.ct_datalen); + ISP_IOXGET_32(isp, &src->rsp.m2.reserved1, dst->rsp.m2.reserved1); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, dst->rsp.m2.ct_fcp_rsp_iudata.ds_base); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_basehi, dst->rsp.m2.ct_fcp_rsp_iudata.ds_basehi); + ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, dst->rsp.m2.ct_fcp_rsp_iudata.ds_count); } } @@ -2305,8 +3252,7 @@ isp_put_enable_lun(ispsoftc_t *isp, lun_entry_t *lesrc, lun_entry_t *ledst) ISP_IOXPUT_32(isp, lesrc->le_flags, &ledst->le_flags); ISP_IOXPUT_16(isp, lesrc->le_timeout, &ledst->le_timeout); for (i = 0; i < 20; i++) { - ISP_IOXPUT_8(isp, lesrc->le_reserved3[i], - &ledst->le_reserved3[i]); + ISP_IOXPUT_8(isp, lesrc->le_reserved3[i], &ledst->le_reserved3[i]); } } @@ -2342,8 +3288,7 @@ isp_get_enable_lun(ispsoftc_t *isp, lun_entry_t *lesrc, lun_entry_t *ledst) ISP_IOXGET_32(isp, &lesrc->le_flags, ledst->le_flags); ISP_IOXGET_16(isp, &lesrc->le_timeout, ledst->le_timeout); for (i = 0; i < 20; i++) { - ISP_IOXGET_8(isp, &lesrc->le_reserved3[i], - ledst->le_reserved3[i]); + ISP_IOXGET_8(isp, &lesrc->le_reserved3[i], ledst->le_reserved3[i]); } } @@ -2378,12 +3323,10 @@ isp_put_notify(ispsoftc_t *isp, in_entry_t *src, in_entry_t *dst) ISP_IOXPUT_8(isp, src->in_msg[i], &dst->in_msg[i]); } for (i = 0; i < IN_RSVDLEN; i++) { - ISP_IOXPUT_8(isp, src->in_reserved3[i], - &dst->in_reserved3[i]); + ISP_IOXPUT_8(isp, src->in_reserved3[i], &dst->in_reserved3[i]); } for (i = 0; i < QLTM_SENSELEN; i++) { - ISP_IOXPUT_8(isp, src->in_sense[i], - &dst->in_sense[i]); + ISP_IOXPUT_8(isp, src->in_sense[i], &dst->in_sense[i]); } } @@ -2418,18 +3361,15 @@ isp_get_notify(ispsoftc_t *isp, in_entry_t *src, in_entry_t *dst) ISP_IOXGET_8(isp, &src->in_msg[i], dst->in_msg[i]); } for (i = 0; i < IN_RSVDLEN; i++) { - ISP_IOXGET_8(isp, &src->in_reserved3[i], - dst->in_reserved3[i]); + ISP_IOXGET_8(isp, &src->in_reserved3[i], dst->in_reserved3[i]); } for (i = 0; i < QLTM_SENSELEN; i++) { - ISP_IOXGET_8(isp, &src->in_sense[i], - dst->in_sense[i]); + ISP_IOXGET_8(isp, &src->in_sense[i], dst->in_sense[i]); } } void -isp_put_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, - in_fcentry_t *dst) +isp_put_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, in_fcentry_t *dst) { isp_put_hdr(isp, &src->in_header, &dst->in_header); ISP_IOXPUT_32(isp, src->in_reserved, &dst->in_reserved); @@ -2443,8 +3383,7 @@ isp_put_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, } void -isp_put_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, - in_fcentry_e_t *dst) +isp_put_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, in_fcentry_e_t *dst) { isp_put_hdr(isp, &src->in_header, &dst->in_header); ISP_IOXPUT_32(isp, src->in_reserved, &dst->in_reserved); @@ -2457,8 +3396,7 @@ isp_put_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, } void -isp_put_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, - in_fcentry_24xx_t *dst) +isp_put_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, in_fcentry_24xx_t *dst) { int i; @@ -2476,22 +3414,25 @@ isp_put_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, ISP_IOXPUT_16(isp, src->in_srr_reloff_lo, &dst->in_srr_reloff_lo); ISP_IOXPUT_16(isp, src->in_srr_iu, &dst->in_srr_iu); ISP_IOXPUT_16(isp, src->in_srr_oxid, &dst->in_srr_oxid); - for (i = 0; i < 18; i++) { - ISP_IOXPUT_8(isp, src->in_reserved3[i], &dst->in_reserved3[i]); + ISP_IOXPUT_16(isp, src->in_nport_id_hi, &dst->in_nport_id_hi); + ISP_IOXPUT_8(isp, src->in_nport_id_lo, &dst->in_nport_id_lo); + ISP_IOXPUT_8(isp, src->in_reserved3, &dst->in_reserved3); + ISP_IOXPUT_16(isp, src->in_np_handle, &dst->in_np_handle); + for (i = 0; i < ASIZE(src->in_reserved4); i++) { + ISP_IOXPUT_8(isp, src->in_reserved4[i], &dst->in_reserved4[i]); } - ISP_IOXPUT_8(isp, src->in_reserved4, &dst->in_reserved4); - ISP_IOXPUT_8(isp, src->in_vpindex, &dst->in_vpindex); - ISP_IOXPUT_32(isp, src->in_reserved5, &dst->in_reserved5); + ISP_IOXPUT_8(isp, src->in_reserved5, &dst->in_reserved5); + ISP_IOXPUT_8(isp, src->in_vpidx, &dst->in_vpidx); + ISP_IOXPUT_32(isp, src->in_reserved6, &dst->in_reserved6); ISP_IOXPUT_16(isp, src->in_portid_lo, &dst->in_portid_lo); ISP_IOXPUT_8(isp, src->in_portid_hi, &dst->in_portid_hi); - ISP_IOXPUT_8(isp, src->in_reserved6, &dst->in_reserved6); - ISP_IOXPUT_16(isp, src->in_reserved7, &dst->in_reserved7); + ISP_IOXPUT_8(isp, src->in_reserved7, &dst->in_reserved7); + ISP_IOXPUT_16(isp, src->in_reserved8, &dst->in_reserved8); ISP_IOXPUT_16(isp, src->in_oxid, &dst->in_oxid); } void -isp_get_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, - in_fcentry_t *dst) +isp_get_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, in_fcentry_t *dst) { isp_get_hdr(isp, &src->in_header, &dst->in_header); ISP_IOXGET_32(isp, &src->in_reserved, dst->in_reserved); @@ -2505,8 +3446,7 @@ isp_get_notify_fc(ispsoftc_t *isp, in_fcentry_t *src, } void -isp_get_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, - in_fcentry_e_t *dst) +isp_get_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, in_fcentry_e_t *dst) { isp_get_hdr(isp, &src->in_header, &dst->in_header); ISP_IOXGET_32(isp, &src->in_reserved, dst->in_reserved); @@ -2519,8 +3459,7 @@ isp_get_notify_fc_e(ispsoftc_t *isp, in_fcentry_e_t *src, } void -isp_get_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, - in_fcentry_24xx_t *dst) +isp_get_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, in_fcentry_24xx_t *dst) { int i; @@ -2538,16 +3477,20 @@ isp_get_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *src, ISP_IOXGET_16(isp, &src->in_srr_reloff_lo, dst->in_srr_reloff_lo); ISP_IOXGET_16(isp, &src->in_srr_iu, dst->in_srr_iu); ISP_IOXGET_16(isp, &src->in_srr_oxid, dst->in_srr_oxid); - for (i = 0; i < 18; i++) { - ISP_IOXGET_8(isp, &src->in_reserved3[i], dst->in_reserved3[i]); + ISP_IOXGET_16(isp, &src->in_nport_id_hi, dst->in_nport_id_hi); + ISP_IOXGET_8(isp, &src->in_nport_id_lo, dst->in_nport_id_lo); + ISP_IOXGET_8(isp, &src->in_reserved3, dst->in_reserved3); + ISP_IOXGET_16(isp, &src->in_np_handle, dst->in_np_handle); + for (i = 0; i < ASIZE(src->in_reserved4); i++) { + ISP_IOXGET_8(isp, &src->in_reserved4[i], dst->in_reserved4[i]); } - ISP_IOXGET_8(isp, &src->in_reserved4, dst->in_reserved4); - ISP_IOXGET_8(isp, &src->in_vpindex, dst->in_vpindex); - ISP_IOXGET_32(isp, &src->in_reserved5, dst->in_reserved5); + ISP_IOXGET_8(isp, &src->in_reserved5, dst->in_reserved5); + ISP_IOXGET_8(isp, &src->in_vpidx, dst->in_vpidx); + ISP_IOXGET_32(isp, &src->in_reserved6, dst->in_reserved6); ISP_IOXGET_16(isp, &src->in_portid_lo, dst->in_portid_lo); ISP_IOXGET_8(isp, &src->in_portid_hi, dst->in_portid_hi); - ISP_IOXGET_8(isp, &src->in_reserved6, dst->in_reserved6); - ISP_IOXGET_16(isp, &src->in_reserved7, dst->in_reserved7); + ISP_IOXGET_8(isp, &src->in_reserved7, dst->in_reserved7); + ISP_IOXGET_16(isp, &src->in_reserved8, dst->in_reserved8); ISP_IOXGET_16(isp, &src->in_oxid, dst->in_oxid); } @@ -2570,8 +3513,7 @@ isp_put_notify_ack(ispsoftc_t *isp, na_entry_t *src, na_entry_t *dst) } ISP_IOXPUT_32(isp, src->na_flags, &dst->na_flags); for (i = 0; i < NA_RSVDLEN; i++) { - ISP_IOXPUT_16(isp, src->na_reserved3[i], - &dst->na_reserved3[i]); + ISP_IOXPUT_16(isp, src->na_reserved3[i], &dst->na_reserved3[i]); } } @@ -2594,14 +3536,12 @@ isp_get_notify_ack(ispsoftc_t *isp, na_entry_t *src, na_entry_t *dst) } ISP_IOXGET_32(isp, &src->na_flags, dst->na_flags); for (i = 0; i < NA_RSVDLEN; i++) { - ISP_IOXGET_16(isp, &src->na_reserved3[i], - dst->na_reserved3[i]); + ISP_IOXGET_16(isp, &src->na_reserved3[i], dst->na_reserved3[i]); } } void -isp_put_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, - na_fcentry_t *dst) +isp_put_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, na_fcentry_t *dst) { int i; isp_put_hdr(isp, &src->na_header, &dst->na_header); @@ -2615,14 +3555,12 @@ isp_put_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, ISP_IOXPUT_16(isp, src->na_task_flags, &dst->na_task_flags); ISP_IOXPUT_16(isp, src->na_seqid, &dst->na_seqid); for (i = 0; i < NA2_RSVDLEN; i++) { - ISP_IOXPUT_16(isp, src->na_reserved3[i], - &dst->na_reserved3[i]); + ISP_IOXPUT_16(isp, src->na_reserved3[i], &dst->na_reserved3[i]); } } void -isp_put_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, - na_fcentry_e_t *dst) +isp_put_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, na_fcentry_e_t *dst) { int i; isp_put_hdr(isp, &src->na_header, &dst->na_header); @@ -2635,14 +3573,12 @@ isp_put_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, ISP_IOXPUT_16(isp, src->na_task_flags, &dst->na_task_flags); ISP_IOXPUT_16(isp, src->na_seqid, &dst->na_seqid); for (i = 0; i < NA2_RSVDLEN; i++) { - ISP_IOXPUT_16(isp, src->na_reserved3[i], - &dst->na_reserved3[i]); + ISP_IOXPUT_16(isp, src->na_reserved3[i], &dst->na_reserved3[i]); } } void -isp_put_notify_24xx_ack(ispsoftc_t *isp, na_fcentry_24xx_t *src, - na_fcentry_24xx_t *dst) +isp_put_notify_24xx_ack(ispsoftc_t *isp, na_fcentry_24xx_t *src, na_fcentry_24xx_t *dst) { int i; @@ -2664,11 +3600,9 @@ isp_put_notify_24xx_ack(ispsoftc_t *isp, na_fcentry_24xx_t *src, ISP_IOXPUT_8(isp, src->na_reserved3[i], &dst->na_reserved3[i]); } ISP_IOXPUT_8(isp, src->na_reserved4, &dst->na_reserved4); - ISP_IOXPUT_8(isp, src->na_vpindex, &dst->na_vpindex); - ISP_IOXPUT_8(isp, src->na_srr_reject_vunique, - &dst->na_srr_reject_vunique); - ISP_IOXPUT_8(isp, src->na_srr_reject_explanation, - &dst->na_srr_reject_explanation); + ISP_IOXPUT_8(isp, src->na_vpidx, &dst->na_vpidx); + ISP_IOXPUT_8(isp, src->na_srr_reject_vunique, &dst->na_srr_reject_vunique); + ISP_IOXPUT_8(isp, src->na_srr_reject_explanation, &dst->na_srr_reject_explanation); ISP_IOXPUT_8(isp, src->na_srr_reject_code, &dst->na_srr_reject_code); ISP_IOXPUT_8(isp, src->na_reserved5, &dst->na_reserved5); for (i = 0; i < 6; i++) { @@ -2678,8 +3612,7 @@ isp_put_notify_24xx_ack(ispsoftc_t *isp, na_fcentry_24xx_t *src, } void -isp_get_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, - na_fcentry_t *dst) +isp_get_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, na_fcentry_t *dst) { int i; isp_get_hdr(isp, &src->na_header, &dst->na_header); @@ -2693,14 +3626,12 @@ isp_get_notify_ack_fc(ispsoftc_t *isp, na_fcentry_t *src, ISP_IOXGET_16(isp, &src->na_task_flags, dst->na_task_flags); ISP_IOXGET_16(isp, &src->na_seqid, dst->na_seqid); for (i = 0; i < NA2_RSVDLEN; i++) { - ISP_IOXGET_16(isp, &src->na_reserved3[i], - dst->na_reserved3[i]); + ISP_IOXGET_16(isp, &src->na_reserved3[i], dst->na_reserved3[i]); } } void -isp_get_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, - na_fcentry_e_t *dst) +isp_get_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, na_fcentry_e_t *dst) { int i; isp_get_hdr(isp, &src->na_header, &dst->na_header); @@ -2713,14 +3644,12 @@ isp_get_notify_ack_fc_e(ispsoftc_t *isp, na_fcentry_e_t *src, ISP_IOXGET_16(isp, &src->na_task_flags, dst->na_task_flags); ISP_IOXGET_16(isp, &src->na_seqid, dst->na_seqid); for (i = 0; i < NA2_RSVDLEN; i++) { - ISP_IOXGET_16(isp, &src->na_reserved3[i], - dst->na_reserved3[i]); + ISP_IOXGET_16(isp, &src->na_reserved3[i], dst->na_reserved3[i]); } } void -isp_get_notify_ack_24xx(ispsoftc_t *isp, na_fcentry_24xx_t *src, - na_fcentry_24xx_t *dst) +isp_get_notify_ack_24xx(ispsoftc_t *isp, na_fcentry_24xx_t *src, na_fcentry_24xx_t *dst) { int i; @@ -2742,11 +3671,9 @@ isp_get_notify_ack_24xx(ispsoftc_t *isp, na_fcentry_24xx_t *src, ISP_IOXGET_8(isp, &src->na_reserved3[i], dst->na_reserved3[i]); } ISP_IOXGET_8(isp, &src->na_reserved4, dst->na_reserved4); - ISP_IOXGET_8(isp, &src->na_vpindex, dst->na_vpindex); - ISP_IOXGET_8(isp, &src->na_srr_reject_vunique, - dst->na_srr_reject_vunique); - ISP_IOXGET_8(isp, &src->na_srr_reject_explanation, - dst->na_srr_reject_explanation); + ISP_IOXGET_8(isp, &src->na_vpidx, dst->na_vpidx); + ISP_IOXGET_8(isp, &src->na_srr_reject_vunique, dst->na_srr_reject_vunique); + ISP_IOXGET_8(isp, &src->na_srr_reject_explanation, dst->na_srr_reject_explanation); ISP_IOXGET_8(isp, &src->na_srr_reject_code, dst->na_srr_reject_code); ISP_IOXGET_8(isp, &src->na_reserved5, dst->na_reserved5); for (i = 0; i < 6; i++) { @@ -2762,8 +3689,7 @@ isp_get_abts(ispsoftc_t *isp, abts_t *src, abts_t *dst) isp_get_hdr(isp, &src->abts_header, &dst->abts_header); for (i = 0; i < 6; i++) { - ISP_IOXGET_8(isp, &src->abts_reserved0[i], - dst->abts_reserved0[i]); + ISP_IOXGET_8(isp, &src->abts_reserved0[i], dst->abts_reserved0[i]); } ISP_IOXGET_16(isp, &src->abts_nphdl, dst->abts_nphdl); ISP_IOXGET_16(isp, &src->abts_reserved1, dst->abts_reserved1); @@ -2785,8 +3711,7 @@ isp_get_abts(ispsoftc_t *isp, abts_t *src, abts_t *dst) ISP_IOXGET_16(isp, &src->abts_ox_id, dst->abts_ox_id); ISP_IOXGET_32(isp, &src->abts_param, dst->abts_param); for (i = 0; i < 16; i++) { - ISP_IOXGET_8(isp, &src->abts_reserved2[i], - dst->abts_reserved2[i]); + ISP_IOXGET_8(isp, &src->abts_reserved2[i], dst->abts_reserved2[i]); } ISP_IOXGET_32(isp, &src->abts_rxid_task, dst->abts_rxid_task); } @@ -2819,43 +3744,27 @@ isp_put_abts_rsp(ispsoftc_t *isp, abts_rsp_t *src, abts_rsp_t *dst) ISP_IOXPUT_16(isp, src->abts_rsp_ox_id, &dst->abts_rsp_ox_id); ISP_IOXPUT_32(isp, src->abts_rsp_param, &dst->abts_rsp_param); if (src->abts_rsp_r_ctl == BA_ACC) { - ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.reserved, - &dst->abts_rsp_payload.ba_acc.reserved); - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_acc.last_seq_id, - &dst->abts_rsp_payload.ba_acc.last_seq_id); - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_acc.seq_id_valid, - &dst->abts_rsp_payload.ba_acc.seq_id_valid); - ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.aborted_rx_id, - &dst->abts_rsp_payload.ba_acc.aborted_rx_id); - ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.aborted_ox_id, - &dst->abts_rsp_payload.ba_acc.aborted_ox_id); - ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.high_seq_cnt, - &dst->abts_rsp_payload.ba_acc.high_seq_cnt); - ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.low_seq_cnt, - &dst->abts_rsp_payload.ba_acc.low_seq_cnt); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.reserved, &dst->abts_rsp_payload.ba_acc.reserved); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_acc.last_seq_id, &dst->abts_rsp_payload.ba_acc.last_seq_id); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_acc.seq_id_valid, &dst->abts_rsp_payload.ba_acc.seq_id_valid); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.aborted_rx_id, &dst->abts_rsp_payload.ba_acc.aborted_rx_id); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.aborted_ox_id, &dst->abts_rsp_payload.ba_acc.aborted_ox_id); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.high_seq_cnt, &dst->abts_rsp_payload.ba_acc.high_seq_cnt); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.low_seq_cnt, &dst->abts_rsp_payload.ba_acc.low_seq_cnt); for (i = 0; i < 4; i++) { - ISP_IOXPUT_16(isp, - src->abts_rsp_payload.ba_acc.reserved2[i], - &dst->abts_rsp_payload.ba_acc.reserved2[i]); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_acc.reserved2[i], &dst->abts_rsp_payload.ba_acc.reserved2[i]); } } else if (src->abts_rsp_r_ctl == BA_RJT) { - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.vendor_unique, - &dst->abts_rsp_payload.ba_rjt.vendor_unique); - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.explanation, - &dst->abts_rsp_payload.ba_rjt.explanation); - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.reason, - &dst->abts_rsp_payload.ba_rjt.reason); - ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.reserved, - &dst->abts_rsp_payload.ba_rjt.reserved); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.vendor_unique, &dst->abts_rsp_payload.ba_rjt.vendor_unique); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.explanation, &dst->abts_rsp_payload.ba_rjt.explanation); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.reason, &dst->abts_rsp_payload.ba_rjt.reason); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.ba_rjt.reserved, &dst->abts_rsp_payload.ba_rjt.reserved); for (i = 0; i < 12; i++) { - ISP_IOXPUT_16(isp, - src->abts_rsp_payload.ba_rjt.reserved2[i], - &dst->abts_rsp_payload.ba_rjt.reserved2[i]); + ISP_IOXPUT_16(isp, src->abts_rsp_payload.ba_rjt.reserved2[i], &dst->abts_rsp_payload.ba_rjt.reserved2[i]); } } else { for (i = 0; i < 16; i++) { - ISP_IOXPUT_8(isp, src->abts_rsp_payload.reserved[i], - &dst->abts_rsp_payload.reserved[i]); + ISP_IOXPUT_8(isp, src->abts_rsp_payload.reserved[i], &dst->abts_rsp_payload.reserved[i]); } } ISP_IOXPUT_32(isp, src->abts_rsp_rxid_task, &dst->abts_rsp_rxid_task); @@ -2889,13 +3798,10 @@ isp_get_abts_rsp(ispsoftc_t *isp, abts_rsp_t *src, abts_rsp_t *dst) ISP_IOXGET_16(isp, &src->abts_rsp_ox_id, dst->abts_rsp_ox_id); ISP_IOXGET_32(isp, &src->abts_rsp_param, dst->abts_rsp_param); for (i = 0; i < 8; i++) { - ISP_IOXGET_8(isp, &src->abts_rsp_payload.rsp.reserved[i], - dst->abts_rsp_payload.rsp.reserved[i]); + ISP_IOXGET_8(isp, &src->abts_rsp_payload.rsp.reserved[i], dst->abts_rsp_payload.rsp.reserved[i]); } - ISP_IOXGET_32(isp, &src->abts_rsp_payload.rsp.subcode1, - dst->abts_rsp_payload.rsp.subcode1); - ISP_IOXGET_32(isp, &src->abts_rsp_payload.rsp.subcode2, - dst->abts_rsp_payload.rsp.subcode2); + ISP_IOXGET_32(isp, &src->abts_rsp_payload.rsp.subcode1, dst->abts_rsp_payload.rsp.subcode1); + ISP_IOXGET_32(isp, &src->abts_rsp_payload.rsp.subcode2, dst->abts_rsp_payload.rsp.subcode2); ISP_IOXGET_32(isp, &src->abts_rsp_rxid_task, dst->abts_rsp_rxid_task); } #endif /* ISP_TARGET_MODE */ diff --git a/sys/dev/isp/isp_library.h b/sys/dev/isp/isp_library.h index a614bb658fe8..9a9e39721cd0 100644 --- a/sys/dev/isp/isp_library.h +++ b/sys/dev/isp/isp_library.h @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,201 +24,190 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ -#ifndef _ISP_LIBRARY_H -#define _ISP_LIBRARY_H +#ifndef _ISP_LIBRARY_H +#define _ISP_LIBRARY_H -extern int isp_save_xs(ispsoftc_t *, XS_T *, uint32_t *); -extern XS_T *isp_find_xs(ispsoftc_t *, uint32_t); -extern uint32_t isp_find_handle(ispsoftc_t *, XS_T *); -extern uint32_t isp_handle_index(uint32_t); -extern void isp_destroy_handle(ispsoftc_t *, uint32_t); -extern int isp_getrqentry(ispsoftc_t *, uint32_t *, uint32_t *, void **); -extern void isp_print_qentry (ispsoftc_t *, char *, int, void *); -extern void isp_print_bytes(ispsoftc_t *, const char *, int, void *); -extern int isp_fc_runstate(ispsoftc_t *, int); -extern void isp_dump_portdb(ispsoftc_t *); -extern void isp_shutdown(ispsoftc_t *); -extern void isp_put_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); -extern void isp_get_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); -extern int isp_get_response_type(ispsoftc_t *, isphdr_t *); -extern void -isp_put_request(ispsoftc_t *, ispreq_t *, ispreq_t *); -extern void -isp_put_marker(ispsoftc_t *, isp_marker_t *, isp_marker_t *); -extern void -isp_put_marker_24xx(ispsoftc_t *, isp_marker_24xx_t *, isp_marker_24xx_t *); -extern void -isp_put_request_t2(ispsoftc_t *, ispreqt2_t *, ispreqt2_t *); -extern void -isp_put_request_t2e(ispsoftc_t *, ispreqt2e_t *, ispreqt2e_t *); -extern void -isp_put_request_t3(ispsoftc_t *, ispreqt3_t *, ispreqt3_t *); -extern void -isp_put_request_t3e(ispsoftc_t *, ispreqt3e_t *, ispreqt3e_t *); -extern void -isp_put_extended_request(ispsoftc_t *, ispextreq_t *, ispextreq_t *); -extern void -isp_put_request_t7(ispsoftc_t *, ispreqt7_t *, ispreqt7_t *); -extern void -isp_put_24xx_abrt(ispsoftc_t *, isp24xx_abrt_t *, isp24xx_abrt_t *); -extern void -isp_put_cont_req(ispsoftc_t *, ispcontreq_t *, ispcontreq_t *); -extern void -isp_put_cont64_req(ispsoftc_t *, ispcontreq64_t *, ispcontreq64_t *); -extern void -isp_get_response(ispsoftc_t *, ispstatusreq_t *, ispstatusreq_t *); -extern void isp_get_24xx_response(ispsoftc_t *, isp24xx_statusreq_t *, - isp24xx_statusreq_t *); -void -isp_get_24xx_abrt(ispsoftc_t *, isp24xx_abrt_t *, isp24xx_abrt_t *); -extern void -isp_get_rio2(ispsoftc_t *, isp_rio2_t *, isp_rio2_t *); -extern void -isp_put_icb(ispsoftc_t *, isp_icb_t *, isp_icb_t *); -extern void -isp_put_icb_2400(ispsoftc_t *, isp_icb_2400_t *, isp_icb_2400_t *); -extern void -isp_get_pdb_21xx(ispsoftc_t *, isp_pdb_21xx_t *, isp_pdb_21xx_t *); -extern void -isp_get_pdb_24xx(ispsoftc_t *, isp_pdb_24xx_t *, isp_pdb_24xx_t *); -extern void -isp_get_plogx(ispsoftc_t *, isp_plogx_t *, isp_plogx_t *); -extern void -isp_put_plogx(ispsoftc_t *, isp_plogx_t *, isp_plogx_t *); -extern void -isp_get_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *, isp_ct_pt_t *); -extern void -isp_get_ms(ispsoftc_t *isp, isp_ms_t *, isp_ms_t *); -extern void -isp_put_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *, isp_ct_pt_t *); -extern void -isp_put_ms(ispsoftc_t *isp, isp_ms_t *, isp_ms_t *); -extern void -isp_put_sns_request(ispsoftc_t *, sns_screq_t *, sns_screq_t *); -extern void -isp_put_gid_ft_request(ispsoftc_t *, sns_gid_ft_req_t *, - sns_gid_ft_req_t *); -extern void -isp_put_gxn_id_request(ispsoftc_t *, sns_gxn_id_req_t *, - sns_gxn_id_req_t *); -extern void -isp_get_sns_response(ispsoftc_t *, sns_scrsp_t *, sns_scrsp_t *, int); -extern void -isp_get_gid_ft_response(ispsoftc_t *, sns_gid_ft_rsp_t *, - sns_gid_ft_rsp_t *, int); -extern void -isp_get_gxn_id_response(ispsoftc_t *, sns_gxn_id_rsp_t *, - sns_gxn_id_rsp_t *); -extern void -isp_get_gff_id_response(ispsoftc_t *, sns_gff_id_rsp_t *, - sns_gff_id_rsp_t *); -extern void -isp_get_ga_nxt_response(ispsoftc_t *, sns_ga_nxt_rsp_t *, - sns_ga_nxt_rsp_t *); -extern void -isp_get_els(ispsoftc_t *, els_t *, els_t *); -extern void -isp_put_els(ispsoftc_t *, els_t *, els_t *); -extern void -isp_get_fc_hdr(ispsoftc_t *, fc_hdr_t *, fc_hdr_t *); -extern void -isp_get_fcp_cmnd_iu(ispsoftc_t *, fcp_cmnd_iu_t *, fcp_cmnd_iu_t *); -extern void isp_put_rft_id(ispsoftc_t *, rft_id_t *, rft_id_t *); -extern void isp_get_ct_hdr(ispsoftc_t *isp, ct_hdr_t *, ct_hdr_t *); -extern void isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *, ct_hdr_t *); +/* + * Common command shipping routine. + * + * This used to be platform specific, but basically once you get the segment + * stuff figured out, you can make all the code in one spot. + */ +typedef enum { ISP_TO_DEVICE, ISP_FROM_DEVICE, ISP_NOXFR} isp_ddir_t; +int isp_send_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t); -#define ISP_HANDLE_MASK 0x7fff +/* + * Handle management functions. + * + * These handles are associate with a command. + */ +int isp_save_xs(ispsoftc_t *, XS_T *, uint32_t *); +XS_T * isp_find_xs(ispsoftc_t *, uint32_t); +uint32_t isp_find_handle(ispsoftc_t *, XS_T *); +uint32_t isp_handle_index(uint32_t); +void isp_destroy_handle(ispsoftc_t *, uint32_t); -#ifdef ISP_TARGET_MODE -#if defined(__NetBSD__) || defined(__OpenBSD__) +/* + * Request Queue allocation + */ +void *isp_getrqentry(ispsoftc_t *); + +/* + * Queue Entry debug functions + */ +void isp_print_qentry (ispsoftc_t *, const char *, int, void *); +void isp_print_bytes(ispsoftc_t *, const char *, int, void *); + +/* + * Fibre Channel specific routines and data. + */ +extern const char *isp_class3_roles[4]; +int isp_fc_runstate(ispsoftc_t *, int, int); +void isp_dump_portdb(ispsoftc_t *, int); + +const char *isp_fc_fw_statename(int); +const char *isp_fc_loop_statename(int); +const char *isp_fc_toponame(fcparam *); + +int isp_fc_change_role(ispsoftc_t *, int, int); + + +/* + * Cleanup + */ +void isp_clear_commands(ispsoftc_t *); + +/* + * Common chip shutdown function + */ +void isp_shutdown(ispsoftc_t *); + +/* + * Put/Get routines to push from CPU view to device view + * or to pull from device view to CPU view for various + * data structures (IOCB) + */ +void isp_put_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); +void isp_get_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); +int isp_get_response_type(ispsoftc_t *, isphdr_t *); +void isp_put_request(ispsoftc_t *, ispreq_t *, ispreq_t *); +void isp_put_marker(ispsoftc_t *, isp_marker_t *, isp_marker_t *); +void isp_put_marker_24xx(ispsoftc_t *, isp_marker_24xx_t *, isp_marker_24xx_t *); +void isp_put_request_t2(ispsoftc_t *, ispreqt2_t *, ispreqt2_t *); +void isp_put_request_t2e(ispsoftc_t *, ispreqt2e_t *, ispreqt2e_t *); +void isp_put_request_t3(ispsoftc_t *, ispreqt3_t *, ispreqt3_t *); +void isp_put_request_t3e(ispsoftc_t *, ispreqt3e_t *, ispreqt3e_t *); +void isp_put_extended_request(ispsoftc_t *, ispextreq_t *, ispextreq_t *); +void isp_put_request_t7(ispsoftc_t *, ispreqt7_t *, ispreqt7_t *); +void isp_put_24xx_tmf(ispsoftc_t *, isp24xx_tmf_t *, isp24xx_tmf_t *); +void isp_put_24xx_abrt(ispsoftc_t *, isp24xx_abrt_t *, isp24xx_abrt_t *); +void isp_put_cont_req(ispsoftc_t *, ispcontreq_t *, ispcontreq_t *); +void isp_put_cont64_req(ispsoftc_t *, ispcontreq64_t *, ispcontreq64_t *); +void isp_get_response(ispsoftc_t *, ispstatusreq_t *, ispstatusreq_t *); +void isp_get_24xx_response(ispsoftc_t *, isp24xx_statusreq_t *, isp24xx_statusreq_t *); +void isp_get_24xx_abrt(ispsoftc_t *, isp24xx_abrt_t *, isp24xx_abrt_t *); +void isp_get_rio2(ispsoftc_t *, isp_rio2_t *, isp_rio2_t *); +void isp_put_icb(ispsoftc_t *, isp_icb_t *, isp_icb_t *); +void isp_put_icb_2400(ispsoftc_t *, isp_icb_2400_t *, isp_icb_2400_t *); +void isp_put_icb_2400_vpinfo(ispsoftc_t *, isp_icb_2400_vpinfo_t *, isp_icb_2400_vpinfo_t *); +void isp_put_vp_port_info(ispsoftc_t *, vp_port_info_t *, vp_port_info_t *); +void isp_get_vp_port_info(ispsoftc_t *, vp_port_info_t *, vp_port_info_t *); +void isp_put_vp_ctrl_info(ispsoftc_t *, vp_ctrl_info_t *, vp_ctrl_info_t *); +void isp_get_vp_ctrl_info(ispsoftc_t *, vp_ctrl_info_t *, vp_ctrl_info_t *); +void isp_put_vp_modify(ispsoftc_t *, vp_modify_t *, vp_modify_t *); +void isp_get_vp_modify(ispsoftc_t *, vp_modify_t *, vp_modify_t *); +void isp_get_pdb_21xx(ispsoftc_t *, isp_pdb_21xx_t *, isp_pdb_21xx_t *); +void isp_get_pdb_24xx(ispsoftc_t *, isp_pdb_24xx_t *, isp_pdb_24xx_t *); +void isp_get_ridacq(ispsoftc_t *, isp_ridacq_t *, isp_ridacq_t *); +void isp_get_plogx(ispsoftc_t *, isp_plogx_t *, isp_plogx_t *); +void isp_put_plogx(ispsoftc_t *, isp_plogx_t *, isp_plogx_t *); +void isp_get_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *, isp_ct_pt_t *); +void isp_get_ms(ispsoftc_t *isp, isp_ms_t *, isp_ms_t *); +void isp_put_ct_pt(ispsoftc_t *isp, isp_ct_pt_t *, isp_ct_pt_t *); +void isp_put_ms(ispsoftc_t *isp, isp_ms_t *, isp_ms_t *); +void isp_put_sns_request(ispsoftc_t *, sns_screq_t *, sns_screq_t *); +void isp_put_gid_ft_request(ispsoftc_t *, sns_gid_ft_req_t *, sns_gid_ft_req_t *); +void isp_put_gxn_id_request(ispsoftc_t *, sns_gxn_id_req_t *, sns_gxn_id_req_t *); +void isp_get_sns_response(ispsoftc_t *, sns_scrsp_t *, sns_scrsp_t *, int); +void isp_get_gid_ft_response(ispsoftc_t *, sns_gid_ft_rsp_t *, sns_gid_ft_rsp_t *, int); +void isp_get_gxn_id_response(ispsoftc_t *, sns_gxn_id_rsp_t *, sns_gxn_id_rsp_t *); +void isp_get_gff_id_response(ispsoftc_t *, sns_gff_id_rsp_t *, sns_gff_id_rsp_t *); +void isp_get_ga_nxt_response(ispsoftc_t *, sns_ga_nxt_rsp_t *, sns_ga_nxt_rsp_t *); +void isp_get_els(ispsoftc_t *, els_t *, els_t *); +void isp_put_els(ispsoftc_t *, els_t *, els_t *); +void isp_get_fc_hdr(ispsoftc_t *, fc_hdr_t *, fc_hdr_t *); +void isp_get_fcp_cmnd_iu(ispsoftc_t *, fcp_cmnd_iu_t *, fcp_cmnd_iu_t *); +void isp_put_rft_id(ispsoftc_t *, rft_id_t *, rft_id_t *); +void isp_get_ct_hdr(ispsoftc_t *isp, ct_hdr_t *, ct_hdr_t *); +void isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *, ct_hdr_t *); + +#define ISP_HANDLE_MASK 0x7fff + +#ifdef ISP_TARGET_MODE +#if defined(__NetBSD__) || defined(__OpenBSD__) #include -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) #include #else #include "isp_target.h" #endif -#define IS_TARGET_HANDLE(x) ((x) & 0x8000) +int isp_send_tgt_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, void *, uint32_t); -extern int isp_save_xs_tgt(ispsoftc_t *, void *, uint32_t *); -extern void *isp_find_xs_tgt(ispsoftc_t *, uint32_t); -extern uint32_t isp_find_tgt_handle(ispsoftc_t *, void *); -extern void isp_destroy_tgt_handle(ispsoftc_t *, uint32_t); +#define IS_TARGET_HANDLE(x) ((x) & 0x8000) -extern void -isp_put_atio(ispsoftc_t *, at_entry_t *, at_entry_t *); -extern void -isp_get_atio(ispsoftc_t *, at_entry_t *, at_entry_t *); -extern void -isp_put_atio2(ispsoftc_t *, at2_entry_t *, at2_entry_t *); -extern void -isp_put_atio2e(ispsoftc_t *, at2e_entry_t *, at2e_entry_t *); -extern void -isp_get_atio2(ispsoftc_t *, at2_entry_t *, at2_entry_t *); -extern void -isp_get_atio2e(ispsoftc_t *, at2e_entry_t *, at2e_entry_t *); -extern void -isp_get_atio7(ispsoftc_t *isp, at7_entry_t *, at7_entry_t *); -extern void -isp_put_ctio(ispsoftc_t *, ct_entry_t *, ct_entry_t *); -extern void -isp_get_ctio(ispsoftc_t *, ct_entry_t *, ct_entry_t *); -extern void -isp_put_ctio2(ispsoftc_t *, ct2_entry_t *, ct2_entry_t *); -extern void -isp_put_ctio2e(ispsoftc_t *, ct2e_entry_t *, ct2e_entry_t *); -extern void -isp_put_ctio7(ispsoftc_t *, ct7_entry_t *, ct7_entry_t *); -extern void -isp_get_ctio2(ispsoftc_t *, ct2_entry_t *, ct2_entry_t *); -extern void -isp_get_ctio2e(ispsoftc_t *, ct2e_entry_t *, ct2e_entry_t *); -extern void -isp_get_ctio7(ispsoftc_t *, ct7_entry_t *, ct7_entry_t *); -extern void -isp_put_enable_lun(ispsoftc_t *, lun_entry_t *, lun_entry_t *); -extern void -isp_get_enable_lun(ispsoftc_t *, lun_entry_t *, lun_entry_t *); -extern void -isp_put_notify(ispsoftc_t *, in_entry_t *, in_entry_t *); -extern void -isp_get_notify(ispsoftc_t *, in_entry_t *, in_entry_t *); -extern void -isp_put_notify_fc(ispsoftc_t *, in_fcentry_t *, in_fcentry_t *); -extern void -isp_put_notify_fc_e(ispsoftc_t *, in_fcentry_e_t *, in_fcentry_e_t *); -extern void -isp_put_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *, in_fcentry_24xx_t *); -extern void -isp_get_notify_fc(ispsoftc_t *, in_fcentry_t *, in_fcentry_t *); -extern void -isp_get_notify_fc_e(ispsoftc_t *, in_fcentry_e_t *, in_fcentry_e_t *); -extern void -isp_get_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *, in_fcentry_24xx_t *); -extern void -isp_put_notify_ack(ispsoftc_t *, na_entry_t *, na_entry_t *); -extern void -isp_get_notify_ack(ispsoftc_t *, na_entry_t *, na_entry_t *); -extern void -isp_put_notify_24xx_ack(ispsoftc_t *, na_fcentry_24xx_t *, na_fcentry_24xx_t *); -extern void -isp_put_notify_ack_fc(ispsoftc_t *, na_fcentry_t *, na_fcentry_t *); -extern void -isp_put_notify_ack_fc_e(ispsoftc_t *, na_fcentry_e_t *, na_fcentry_e_t *); -extern void isp_put_notify_ack_24xx(ispsoftc_t *, na_fcentry_24xx_t *, - na_fcentry_24xx_t *); -extern void -isp_get_notify_ack_fc(ispsoftc_t *, na_fcentry_t *, na_fcentry_t *); -extern void -isp_get_notify_ack_fc_e(ispsoftc_t *, na_fcentry_e_t *, na_fcentry_e_t *); -extern void isp_get_notify_ack_24xx(ispsoftc_t *, na_fcentry_24xx_t *, - na_fcentry_24xx_t *); -extern void -isp_get_abts(ispsoftc_t *, abts_t *, abts_t *); -extern void -isp_put_abts_rsp(ispsoftc_t *, abts_rsp_t *, abts_rsp_t *); -extern void -isp_get_abts_rsp(ispsoftc_t *, abts_rsp_t *, abts_rsp_t *); -#endif /* ISP_TARGET_MODE */ -#endif /* _ISP_LIBRARY_H */ +int isp_save_xs_tgt(ispsoftc_t *, void *, uint32_t *); +void *isp_find_xs_tgt(ispsoftc_t *, uint32_t); +uint32_t isp_find_tgt_handle(ispsoftc_t *, void *); +void isp_destroy_tgt_handle(ispsoftc_t *, uint32_t); + +int isp_find_pdb_by_wwn(ispsoftc_t *, int, uint64_t, fcportdb_t **); +int isp_find_pdb_by_loopid(ispsoftc_t *, int, uint32_t, fcportdb_t **); +int isp_find_pdb_by_sid(ispsoftc_t *, int, uint32_t, fcportdb_t **); +void isp_find_chan_by_did(ispsoftc_t *, uint32_t, uint16_t *); +void isp_add_wwn_entry(ispsoftc_t *, int, uint64_t, uint16_t, uint32_t); +void isp_del_wwn_entry(ispsoftc_t *, int, uint64_t, uint16_t, uint32_t); +void isp_del_all_wwn_entries(ispsoftc_t *, int); +void isp_del_wwn_entries(ispsoftc_t *, isp_notify_t *); + +void isp_put_atio(ispsoftc_t *, at_entry_t *, at_entry_t *); +void isp_get_atio(ispsoftc_t *, at_entry_t *, at_entry_t *); +void isp_put_atio2(ispsoftc_t *, at2_entry_t *, at2_entry_t *); +void isp_put_atio2e(ispsoftc_t *, at2e_entry_t *, at2e_entry_t *); +void isp_get_atio2(ispsoftc_t *, at2_entry_t *, at2_entry_t *); +void isp_get_atio2e(ispsoftc_t *, at2e_entry_t *, at2e_entry_t *); +void isp_get_atio7(ispsoftc_t *isp, at7_entry_t *, at7_entry_t *); +void isp_put_ctio(ispsoftc_t *, ct_entry_t *, ct_entry_t *); +void isp_get_ctio(ispsoftc_t *, ct_entry_t *, ct_entry_t *); +void isp_put_ctio2(ispsoftc_t *, ct2_entry_t *, ct2_entry_t *); +void isp_put_ctio2e(ispsoftc_t *, ct2e_entry_t *, ct2e_entry_t *); +void isp_put_ctio7(ispsoftc_t *, ct7_entry_t *, ct7_entry_t *); +void isp_get_ctio2(ispsoftc_t *, ct2_entry_t *, ct2_entry_t *); +void isp_get_ctio2e(ispsoftc_t *, ct2e_entry_t *, ct2e_entry_t *); +void isp_get_ctio7(ispsoftc_t *, ct7_entry_t *, ct7_entry_t *); +void isp_put_enable_lun(ispsoftc_t *, lun_entry_t *, lun_entry_t *); +void isp_get_enable_lun(ispsoftc_t *, lun_entry_t *, lun_entry_t *); +void isp_put_notify(ispsoftc_t *, in_entry_t *, in_entry_t *); +void isp_get_notify(ispsoftc_t *, in_entry_t *, in_entry_t *); +void isp_put_notify_fc(ispsoftc_t *, in_fcentry_t *, in_fcentry_t *); +void isp_put_notify_fc_e(ispsoftc_t *, in_fcentry_e_t *, in_fcentry_e_t *); +void isp_put_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *, in_fcentry_24xx_t *); +void isp_get_notify_fc(ispsoftc_t *, in_fcentry_t *, in_fcentry_t *); +void isp_get_notify_fc_e(ispsoftc_t *, in_fcentry_e_t *, in_fcentry_e_t *); +void isp_get_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *, in_fcentry_24xx_t *); +void isp_put_notify_ack(ispsoftc_t *, na_entry_t *, na_entry_t *); +void isp_get_notify_ack(ispsoftc_t *, na_entry_t *, na_entry_t *); +void isp_put_notify_24xx_ack(ispsoftc_t *, na_fcentry_24xx_t *, na_fcentry_24xx_t *); +void isp_put_notify_ack_fc(ispsoftc_t *, na_fcentry_t *, na_fcentry_t *); +void isp_put_notify_ack_fc_e(ispsoftc_t *, na_fcentry_e_t *, na_fcentry_e_t *); +void isp_put_notify_ack_24xx(ispsoftc_t *, na_fcentry_24xx_t *, na_fcentry_24xx_t *); +void isp_get_notify_ack_fc(ispsoftc_t *, na_fcentry_t *, na_fcentry_t *); +void isp_get_notify_ack_fc_e(ispsoftc_t *, na_fcentry_e_t *, na_fcentry_e_t *); +void isp_get_notify_ack_24xx(ispsoftc_t *, na_fcentry_24xx_t *, na_fcentry_24xx_t *); +void isp_get_abts(ispsoftc_t *, abts_t *, abts_t *); +void isp_put_abts_rsp(ispsoftc_t *, abts_rsp_t *, abts_rsp_t *); +void isp_get_abts_rsp(ispsoftc_t *, abts_rsp_t *, abts_rsp_t *); +#endif /* ISP_TARGET_MODE */ +#endif /* _ISP_LIBRARY_H */ diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index 526337ccd7a2..47dd350887e6 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997-2006 by Matthew Jacob + * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,47 +34,31 @@ __FBSDID("$FreeBSD$"); #include #include #include -#if __FreeBSD_version >= 700000 #include #include -#endif #include -#if __FreeBSD_version < 500000 -#include -#include -#include -#include -#else #include #include #include -#endif #include #include #include #include +#include #include -#if __FreeBSD_version < 500000 -#define BUS_PROBE_DEFAULT 0 -#endif - static uint32_t isp_pci_rd_reg(ispsoftc_t *, int); static void isp_pci_wr_reg(ispsoftc_t *, int, uint32_t); static uint32_t isp_pci_rd_reg_1080(ispsoftc_t *, int); static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint32_t); static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int); static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t); -static int -isp_pci_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); -static int -isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); -static int -isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); +static int isp_pci_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); +static int isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); +static int isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); static int isp_pci_mbxdma(ispsoftc_t *); -static int -isp_pci_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); +static int isp_pci_dmasetup(ispsoftc_t *, XS_T *, void *); static void isp_pci_reset0(ispsoftc_t *); @@ -171,6 +155,18 @@ static struct ispmdvec mdvec_2400 = { NULL }; +static struct ispmdvec mdvec_2500 = { + isp_pci_rd_isr_2400, + isp_pci_rd_reg_2400, + isp_pci_wr_reg_2400, + isp_pci_mbxdma, + isp_pci_dmasetup, + isp_common_dmateardown, + isp_pci_reset0, + isp_pci_reset1, + NULL +}; + #ifndef PCIM_CMD_INVEN #define PCIM_CMD_INVEN 0x10 #endif @@ -259,6 +255,10 @@ static struct ispmdvec mdvec_2400 = { #define PCI_PRODUCT_QLOGIC_ISP2432 0x2432 #endif +#ifndef PCI_PRODUCT_QLOGIC_ISP2532 +#define PCI_PRODUCT_QLOGIC_ISP2532 0x2532 +#endif + #ifndef PCI_PRODUCT_QLOGIC_ISP6312 #define PCI_PRODUCT_QLOGIC_ISP6312 0x6312 #endif @@ -307,6 +307,9 @@ static struct ispmdvec mdvec_2400 = { #define PCI_QLOGIC_ISP2432 \ ((PCI_PRODUCT_QLOGIC_ISP2432 << 16) | PCI_VENDOR_QLOGIC) +#define PCI_QLOGIC_ISP2532 \ + ((PCI_PRODUCT_QLOGIC_ISP2532 << 16) | PCI_VENDOR_QLOGIC) + #define PCI_QLOGIC_ISP6312 \ ((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC) @@ -337,9 +340,7 @@ struct isp_pcisoftc { void * ih; int16_t pci_poff[_NREG_BLKS]; bus_dma_tag_t dmat; -#if __FreeBSD_version > 700025 int msicount; -#endif }; @@ -356,14 +357,11 @@ static driver_t isp_pci_driver = { }; static devclass_t isp_devclass; DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); -#if __FreeBSD_version < 700000 -extern ispfwfunc *isp_get_firmware_p; -#endif static int isp_pci_probe(device_t dev) { - switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { + switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { case PCI_QLOGIC_ISP1020: device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); break; @@ -406,6 +404,9 @@ isp_pci_probe(device_t dev) case PCI_QLOGIC_ISP2432: device_set_desc(dev, "Qlogic ISP 2432 PCI FC-AL Adapter"); break; + case PCI_QLOGIC_ISP2532: + device_set_desc(dev, "Qlogic ISP 2532 PCI FC-AL Adapter"); + break; case PCI_QLOGIC_ISP6312: device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter"); break; @@ -429,176 +430,8 @@ isp_pci_probe(device_t dev) return (BUS_PROBE_DEFAULT); } -#if __FreeBSD_version < 500000 static void -isp_get_generic_options(device_t dev, ispsoftc_t *isp) -{ - int bitmap, unit; - - unit = device_get_unit(dev); - if (getenv_int("isp_disable", &bitmap)) { - if (bitmap & (1 << unit)) { - isp->isp_osinfo.disabled = 1; - return; - } - } - if (getenv_int("isp_no_fwload", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts |= ISP_CFG_NORELOAD; - } - if (getenv_int("isp_fwload", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts &= ~ISP_CFG_NORELOAD; - } - if (getenv_int("isp_no_nvram", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts |= ISP_CFG_NONVRAM; - } - if (getenv_int("isp_nvram", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts &= ~ISP_CFG_NONVRAM; - } - - bitmap = 0; - (void) getenv_int("isp_debug", &bitmap); - if (bitmap) { - isp->isp_dblev = bitmap; - } else { - isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; - } - if (bootverbose) { - isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; - } - - bitmap = 0; - if (getenv_int("role", &bitmap)) { - isp->isp_role = bitmap; - } else { - isp->isp_role = ISP_DEFAULT_ROLES; - } - -} - -static void -isp_get_pci_options(device_t dev, int *m1, int *m2) -{ - int bitmap; - int unit = device_get_unit(dev); - - *m1 = PCIM_CMD_MEMEN; - *m2 = PCIM_CMD_PORTEN; - if (getenv_int("isp_mem_map", &bitmap)) { - if (bitmap & (1 << unit)) { - *m1 = PCIM_CMD_MEMEN; - *m2 = PCIM_CMD_PORTEN; - } - } - bitmap = 0; - if (getenv_int("isp_io_map", &bitmap)) { - if (bitmap & (1 << unit)) { - *m1 = PCIM_CMD_PORTEN; - *m2 = PCIM_CMD_MEMEN; - } - } -} - -static void -isp_get_specific_options(device_t dev, ispsoftc_t *isp) -{ - uint64_t wwn; - int bitmap; - int unit = device_get_unit(dev); - - - if (IS_SCSI(isp)) { - return; - } - - if (getenv_int("isp_fcduplex", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; - } - if (getenv_int("isp_no_fcduplex", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; - } - if (getenv_int("isp_nport", &bitmap)) { - if (bitmap & (1 << unit)) - isp->isp_confopts |= ISP_CFG_NPORT; - } - - /* - * Because the resource_*_value functions can neither return - * 64 bit integer values, nor can they be directly coerced - * to interpret the right hand side of the assignment as - * you want them to interpret it, we have to force WWN - * hint replacement to specify WWN strings with a leading - * 'w' (e..g w50000000aaaa0001). Sigh. - */ - if (getenv_quad("isp_portwwn", &wwn)) { - isp->isp_osinfo.default_port_wwn = wwn; - isp->isp_confopts |= ISP_CFG_OWNWWPN; - } - if (isp->isp_osinfo.default_port_wwn == 0) { - isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; - } - - if (getenv_quad("isp_nodewwn", &wwn)) { - isp->isp_osinfo.default_node_wwn = wwn; - isp->isp_confopts |= ISP_CFG_OWNWWNN; - } - if (isp->isp_osinfo.default_node_wwn == 0) { - isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; - } - - bitmap = 0; - (void) getenv_int("isp_fabric_hysteresis", &bitmap); - if (bitmap >= 0 && bitmap < 256) { - isp->isp_osinfo.hysteresis = bitmap; - } else { - isp->isp_osinfo.hysteresis = isp_fabric_hysteresis; - } - - bitmap = 0; - (void) getenv_int("isp_loop_down_limit", &bitmap); - if (bitmap >= 0 && bitmap < 0xffff) { - isp->isp_osinfo.loop_down_limit = bitmap; - } else { - isp->isp_osinfo.loop_down_limit = isp_loop_down_limit; - } - - bitmap = 0; - (void) getenv_int("isp_gone_device_time", &bitmap); - if (bitmap >= 0 && bitmap < 0xffff) { - isp->isp_osinfo.gone_device_time = bitmap; - } else { - isp->isp_osinfo.gone_device_time = isp_gone_device_time; - } -#ifdef ISP_FW_CRASH_DUMP - bitmap = 0; - if (getenv_int("isp_fw_dump_enable", &bitmap)) { - if (bitmap & (1 << unit) { - size_t amt = 0; - if (IS_2200(isp)) { - amt = QLA2200_RISC_IMAGE_DUMP_SIZE; - } else if (IS_23XX(isp)) { - amt = QLA2300_RISC_IMAGE_DUMP_SIZE; - } - if (amt) { - FCPARAM(isp)->isp_dump_data = - malloc(amt, M_DEVBUF, M_WAITOK); - memset(FCPARAM(isp)->isp_dump_data, 0, amt); - } else { - device_printf(dev, - "f/w crash dumps not supported for card\n"); - } - } - } -#endif -} -#else -static void -isp_get_generic_options(device_t dev, ispsoftc_t *isp) +isp_get_generic_options(device_t dev, ispsoftc_t *isp, int *nvp) { int tval; @@ -606,41 +439,22 @@ isp_get_generic_options(device_t dev, ispsoftc_t *isp) * Figure out if we're supposed to skip this one. */ tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "disable", &tval) == 0 && tval) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "disable", &tval) == 0 && tval) { device_printf(dev, "disabled at user request\n"); isp->isp_osinfo.disabled = 1; return; } - tval = -1; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "role", &tval) == 0 && tval != -1) { - tval &= (ISP_ROLE_INITIATOR|ISP_ROLE_TARGET); - isp->isp_role = tval; - device_printf(dev, "setting role to 0x%x\n", isp->isp_role); - } else { -#ifdef ISP_TARGET_MODE - isp->isp_role = ISP_ROLE_TARGET; -#else - isp->isp_role = ISP_DEFAULT_ROLES; -#endif - } - tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "fwload_disable", &tval) == 0 && tval != 0) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fwload_disable", &tval) == 0 && tval != 0) { isp->isp_confopts |= ISP_CFG_NORELOAD; } tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "ignore_nvram", &tval) == 0 && tval != 0) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "ignore_nvram", &tval) == 0 && tval != 0) { isp->isp_confopts |= ISP_CFG_NONVRAM; } - tval = 0; - (void) resource_int_value(device_get_name(dev), device_get_unit(dev), - "debug", &tval); + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "debug", &tval); if (tval) { isp->isp_dblev = tval; } else { @@ -649,7 +463,23 @@ isp_get_generic_options(device_t dev, ispsoftc_t *isp) if (bootverbose) { isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; } + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "vports", &tval); + if (tval > 0 && tval < 127) { + *nvp = tval; + } else { + *nvp = 0; + } + tval = 1; + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "autoconfig", &tval); + isp_autoconfig = tval; + tval = 7; + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "quickboot_time", &tval); + isp_quickboot_time = tval; + tval = 0; + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "forcemulti", &tval) == 0 && tval != 0) { + isp->isp_osinfo.forcemulti = 1; + } } static void @@ -666,70 +496,68 @@ isp_get_pci_options(device_t dev, int *m1, int *m2) *m2 = PCIM_CMD_PORTEN; tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "prefer_iomap", &tval) == 0 && tval != 0) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_iomap", &tval) == 0 && tval != 0) { *m1 = PCIM_CMD_PORTEN; *m2 = PCIM_CMD_MEMEN; } tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "prefer_memmap", &tval) == 0 && tval != 0) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_memmap", &tval) == 0 && tval != 0) { *m1 = PCIM_CMD_MEMEN; *m2 = PCIM_CMD_PORTEN; } } static void -isp_get_specific_options(device_t dev, ispsoftc_t *isp) +isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp) { const char *sptr; int tval; - isp->isp_osinfo.default_id = -1; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "iid", &tval) == 0) { - isp->isp_osinfo.default_id = tval; + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "iid", &tval)) { + if (IS_FC(isp)) { + ISP_FC_PC(isp, chan)->default_id = 109 - chan; + } else { + ISP_SPI_PC(isp, chan)->iid = 7; + } + } else { + if (IS_FC(isp)) { + ISP_FC_PC(isp, chan)->default_id = tval - chan; + } else { + ISP_SPI_PC(isp, chan)->iid = tval; + } isp->isp_confopts |= ISP_CFG_OWNLOOPID; } - if (isp->isp_osinfo.default_id == -1) { - if (IS_FC(isp)) { - isp->isp_osinfo.default_id = 109; - } else { - isp->isp_osinfo.default_id = 7; + + tval = -1; + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "role", &tval) == 0) { + switch (tval) { + case ISP_ROLE_NONE: + case ISP_ROLE_INITIATOR: + case ISP_ROLE_TARGET: + case ISP_ROLE_INITIATOR|ISP_ROLE_TARGET: + device_printf(dev, "setting role to 0x%x\n", tval); + break; + default: + tval = -1; + break; } } + if (tval == -1) { + tval = ISP_DEFAULT_ROLES; + } if (IS_SCSI(isp)) { + ISP_SPI_PC(isp, chan)->role = tval; return; } + ISP_FC_PC(isp, chan)->role = tval; tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "fullduplex", &tval) == 0 && tval != 0) { + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fullduplex", &tval) == 0 && tval != 0) { isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; } -#ifdef ISP_FW_CRASH_DUMP - tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "fw_dump_enable", &tval) == 0 && tval != 0) { - size_t amt = 0; - if (IS_2200(isp)) { - amt = QLA2200_RISC_IMAGE_DUMP_SIZE; - } else if (IS_23XX(isp)) { - amt = QLA2300_RISC_IMAGE_DUMP_SIZE; - } - if (amt) { - FCPARAM(isp)->isp_dump_data = - malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO); - } else { - device_printf(dev, - "f/w crash dumps not supported for this model\n"); - } - } -#endif sptr = 0; - if (resource_string_value(device_get_name(dev), device_get_unit(dev), - "topology", (const char **) &sptr) == 0 && sptr != 0) { + if (resource_string_value(device_get_name(dev), device_get_unit(dev), "topology", (const char **) &sptr) == 0 && sptr != 0) { if (strcmp(sptr, "lport") == 0) { isp->isp_confopts |= ISP_CFG_LPORT; } else if (strcmp(sptr, "nport") == 0) { @@ -750,81 +578,63 @@ isp_get_specific_options(device_t dev, ispsoftc_t *isp) * 'w' (e..g w50000000aaaa0001). Sigh. */ sptr = 0; - tval = resource_string_value(device_get_name(dev), device_get_unit(dev), - "portwwn", (const char **) &sptr); + tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "portwwn", (const char **) &sptr); if (tval == 0 && sptr != 0 && *sptr++ == 'w') { char *eptr = 0; - isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); - if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { + ISP_FC_PC(isp, chan)->def_wwpn = strtouq(sptr, &eptr, 16); + if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwpn == -1) { device_printf(dev, "mangled portwwn hint '%s'\n", sptr); - isp->isp_osinfo.default_port_wwn = 0; - } else { - isp->isp_confopts |= ISP_CFG_OWNWWPN; + ISP_FC_PC(isp, chan)->def_wwpn = 0; } } - if (isp->isp_osinfo.default_port_wwn == 0) { - isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; - } sptr = 0; - tval = resource_string_value(device_get_name(dev), device_get_unit(dev), - "nodewwn", (const char **) &sptr); + tval = resource_string_value(device_get_name(dev), device_get_unit(dev), "nodewwn", (const char **) &sptr); if (tval == 0 && sptr != 0 && *sptr++ == 'w') { char *eptr = 0; - isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); - if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { + ISP_FC_PC(isp, chan)->def_wwnn = strtouq(sptr, &eptr, 16); + if (eptr < sptr + 16 || ISP_FC_PC(isp, chan)->def_wwnn == 0) { device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); - isp->isp_osinfo.default_node_wwn = 0; - } else { - isp->isp_confopts |= ISP_CFG_OWNWWNN; + ISP_FC_PC(isp, chan)->def_wwnn = 0; } } - if (isp->isp_osinfo.default_node_wwn == 0) { - isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; - } - tval = 0; - (void) resource_int_value(device_get_name(dev), device_get_unit(dev), - "hysteresis", &tval); + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "hysteresis", &tval); if (tval >= 0 && tval < 256) { - isp->isp_osinfo.hysteresis = tval; + ISP_FC_PC(isp, chan)->hysteresis = tval; } else { - isp->isp_osinfo.hysteresis = isp_fabric_hysteresis; + ISP_FC_PC(isp, chan)->hysteresis = isp_fabric_hysteresis; } tval = -1; - (void) resource_int_value(device_get_name(dev), device_get_unit(dev), - "loop_down_limit", &tval); + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "loop_down_limit", &tval); if (tval >= 0 && tval < 0xffff) { - isp->isp_osinfo.loop_down_limit = tval; + ISP_FC_PC(isp, chan)->loop_down_limit = tval; } else { - isp->isp_osinfo.loop_down_limit = isp_loop_down_limit; + ISP_FC_PC(isp, chan)->loop_down_limit = isp_loop_down_limit; } tval = -1; - (void) resource_int_value(device_get_name(dev), device_get_unit(dev), - "gone_device_time", &tval); + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), "gone_device_time", &tval); if (tval >= 0 && tval < 0xffff) { - isp->isp_osinfo.gone_device_time = tval; + ISP_FC_PC(isp, chan)->gone_device_time = tval; } else { - isp->isp_osinfo.gone_device_time = isp_gone_device_time; + ISP_FC_PC(isp, chan)->gone_device_time = isp_gone_device_time; } } -#endif static int isp_pci_attach(device_t dev) { struct resource *regs, *irq; - int rtp, rgd, iqd, m1, m2; - uint32_t data, cmd, linesz, psize, basetype; + int rtp, rgd, iqd, i, m1, m2, locksetup = 0; + int isp_nvports = 0; + uint32_t data, cmd, linesz, did; struct isp_pcisoftc *pcs; ispsoftc_t *isp = NULL; - struct ispmdvec *mdvp; -#if __FreeBSD_version >= 500000 - int locksetup = 0; -#endif + size_t psize, xsize; + char fwname[32]; pcs = device_get_softc(dev); if (pcs == NULL) { @@ -832,13 +642,16 @@ isp_pci_attach(device_t dev) return (ENOMEM); } memset(pcs, 0, sizeof (*pcs)); + pcs->pci_dev = dev; isp = &pcs->pci_isp; + isp->isp_dev = dev; + isp->isp_nchan = 1; /* * Get Generic Options */ - isp_get_generic_options(dev, isp); + isp_get_generic_options(dev, isp, &isp_nvports); /* * Check to see if options have us disabled @@ -875,68 +688,62 @@ isp_pci_attach(device_t dev) goto bad; } if (bootverbose) { - device_printf(dev, "using %s space register mapping\n", - (rgd == IO_MAP_REG)? "I/O" : "Memory"); + device_printf(dev, "using %s space register mapping\n", (rgd == IO_MAP_REG)? "I/O" : "Memory"); } - pcs->pci_dev = dev; - pcs->pci_reg = regs; isp->isp_bus_tag = rman_get_bustag(regs); isp->isp_bus_handle = rman_get_bushandle(regs); + pcs->pci_dev = dev; + pcs->pci_reg = regs; pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; - mdvp = &mdvec; - basetype = ISP_HA_SCSI_UNKNOWN; - psize = sizeof (sdparam); - if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { - mdvp = &mdvec; - basetype = ISP_HA_SCSI_UNKNOWN; - psize = sizeof (sdparam); - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { - mdvp = &mdvec_1080; - basetype = ISP_HA_SCSI_1080; - psize = sizeof (sdparam); - pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = - ISP1080_DMA_REGS_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { - mdvp = &mdvec_1080; - basetype = ISP_HA_SCSI_1240; - psize = 2 * sizeof (sdparam); - pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = - ISP1080_DMA_REGS_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { - mdvp = &mdvec_1080; - basetype = ISP_HA_SCSI_1280; - psize = 2 * sizeof (sdparam); - pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = - ISP1080_DMA_REGS_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP10160) { - mdvp = &mdvec_12160; - basetype = ISP_HA_SCSI_10160; - psize = sizeof (sdparam); - pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = - ISP1080_DMA_REGS_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { - mdvp = &mdvec_12160; - basetype = ISP_HA_SCSI_12160; - psize = 2 * sizeof (sdparam); - pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = - ISP1080_DMA_REGS_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { - mdvp = &mdvec_2100; - basetype = ISP_HA_FC_2100; - psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2100_OFF; + + switch (pci_get_devid(dev)) { + case PCI_QLOGIC_ISP1020: + did = 0x1040; + isp->isp_mdvec = &mdvec; + isp->isp_type = ISP_HA_SCSI_UNKNOWN; + break; + case PCI_QLOGIC_ISP1080: + did = 0x1080; + isp->isp_mdvec = &mdvec_1080; + isp->isp_type = ISP_HA_SCSI_1080; + pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF; + break; + case PCI_QLOGIC_ISP1240: + did = 0x1080; + isp->isp_mdvec = &mdvec_1080; + isp->isp_type = ISP_HA_SCSI_1240; + isp->isp_nchan = 2; + pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF; + break; + case PCI_QLOGIC_ISP1280: + did = 0x1080; + isp->isp_mdvec = &mdvec_1080; + isp->isp_type = ISP_HA_SCSI_1280; + pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF; + break; + case PCI_QLOGIC_ISP10160: + did = 0x12160; + isp->isp_mdvec = &mdvec_12160; + isp->isp_type = ISP_HA_SCSI_10160; + pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF; + break; + case PCI_QLOGIC_ISP12160: + did = 0x12160; + isp->isp_nchan = 2; + isp->isp_mdvec = &mdvec_12160; + isp->isp_type = ISP_HA_SCSI_12160; + pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF; + break; + case PCI_QLOGIC_ISP2100: + did = 0x2100; + isp->isp_mdvec = &mdvec_2100; + isp->isp_type = ISP_HA_FC_2100; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF; if (pci_get_revid(dev) < 3) { /* * XXX: Need to get the actual revision @@ -946,121 +753,100 @@ isp_pci_attach(device_t dev) */ linesz = 1; } + break; + case PCI_QLOGIC_ISP2200: + did = 0x2200; + isp->isp_mdvec = &mdvec_2200; + isp->isp_type = ISP_HA_FC_2200; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF; + break; + case PCI_QLOGIC_ISP2300: + did = 0x2300; + isp->isp_mdvec = &mdvec_2300; + isp->isp_type = ISP_HA_FC_2300; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF; + break; + case PCI_QLOGIC_ISP2312: + case PCI_QLOGIC_ISP6312: + did = 0x2300; + isp->isp_mdvec = &mdvec_2300; + isp->isp_type = ISP_HA_FC_2312; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF; + break; + case PCI_QLOGIC_ISP2322: + case PCI_QLOGIC_ISP6322: + did = 0x2322; + isp->isp_mdvec = &mdvec_2300; + isp->isp_type = ISP_HA_FC_2322; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF; + break; + case PCI_QLOGIC_ISP2422: + case PCI_QLOGIC_ISP2432: + did = 0x2400; + isp->isp_nchan += isp_nvports; + isp->isp_mdvec = &mdvec_2400; + isp->isp_type = ISP_HA_FC_2400; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF; + break; + case PCI_QLOGIC_ISP2532: + did = 0x2500; + isp->isp_nchan += isp_nvports; + isp->isp_mdvec = &mdvec_2500; + isp->isp_type = ISP_HA_FC_2500; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF; + break; + default: + device_printf(dev, "unknown device type\n"); + goto bad; + break; } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { - mdvp = &mdvec_2200; - basetype = ISP_HA_FC_2200; + isp->isp_revision = pci_get_revid(dev); + + if (IS_FC(isp)) { psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2100_OFF; + xsize = sizeof (struct isp_fc); + } else { + psize = sizeof (sdparam); + xsize = sizeof (struct isp_spi); } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) { - mdvp = &mdvec_2300; - basetype = ISP_HA_FC_2300; - psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2300_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312 || - pci_get_devid(dev) == PCI_QLOGIC_ISP6312) { - mdvp = &mdvec_2300; - basetype = ISP_HA_FC_2312; - psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2300_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2322 || - pci_get_devid(dev) == PCI_QLOGIC_ISP6322) { - mdvp = &mdvec_2300; - basetype = ISP_HA_FC_2322; - psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2300_OFF; - } - if (pci_get_devid(dev) == PCI_QLOGIC_ISP2422 || - pci_get_devid(dev) == PCI_QLOGIC_ISP2432) { - mdvp = &mdvec_2400; - basetype = ISP_HA_FC_2400; - psize = sizeof (fcparam); - pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = - PCI_MBOX_REGS2400_OFF; - } - isp = &pcs->pci_isp; + psize *= isp->isp_nchan; + xsize *= isp->isp_nchan; isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); if (isp->isp_param == NULL) { device_printf(dev, "cannot allocate parameter data\n"); goto bad; } - isp->isp_mdvec = mdvp; - isp->isp_type = basetype; - isp->isp_revision = pci_get_revid(dev); - isp->isp_dev = dev; + isp->isp_osinfo.pc.ptr = malloc(xsize, M_DEVBUF, M_NOWAIT | M_ZERO); + if (isp->isp_osinfo.pc.ptr == NULL) { + device_printf(dev, "cannot allocate parameter data\n"); + goto bad; + } /* * Now that we know who we are (roughly) get/set specific options */ - isp_get_specific_options(dev, isp); + for (i = 0; i < isp->isp_nchan; i++) { + isp_get_specific_options(dev, i, isp); + } -#if __FreeBSD_version >= 700000 /* - * Try and find firmware for this device. + * The 'it' suffix really only matters for SCSI cards in target mode. */ - { - char fwname[32]; - unsigned int did = pci_get_device(dev); - - /* - * Map a few pci ids to fw names - */ - switch (did) { - case PCI_PRODUCT_QLOGIC_ISP1020: - did = 0x1040; - break; - case PCI_PRODUCT_QLOGIC_ISP1240: - did = 0x1080; - break; - case PCI_PRODUCT_QLOGIC_ISP10160: - case PCI_PRODUCT_QLOGIC_ISP12160: - did = 0x12160; - break; - case PCI_PRODUCT_QLOGIC_ISP6312: - case PCI_PRODUCT_QLOGIC_ISP2312: - did = 0x2300; - break; - case PCI_PRODUCT_QLOGIC_ISP6322: - did = 0x2322; - break; - case PCI_PRODUCT_QLOGIC_ISP2422: - case PCI_PRODUCT_QLOGIC_ISP2432: - did = 0x2400; - break; - default: - break; - } - - isp->isp_osinfo.fw = NULL; - if (isp->isp_role & ISP_ROLE_TARGET) { - snprintf(fwname, sizeof (fwname), "isp_%04x_it", did); - isp->isp_osinfo.fw = firmware_get(fwname); - } - if (isp->isp_osinfo.fw == NULL) { - snprintf(fwname, sizeof (fwname), "isp_%04x", did); - isp->isp_osinfo.fw = firmware_get(fwname); - } - if (isp->isp_osinfo.fw != NULL) { - isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data; - } + isp->isp_osinfo.fw = NULL; + if (IS_SCSI(isp) && (ISP_SPI_PC(isp, 0)->role & ISP_ROLE_TARGET)) { + snprintf(fwname, sizeof (fwname), "isp_%04x_it", did); + isp->isp_osinfo.fw = firmware_get(fwname); + } else if (IS_24XX(isp) && (isp->isp_nchan > 1 || isp->isp_osinfo.forcemulti)) { + snprintf(fwname, sizeof (fwname), "isp_%04x_multi", did); + isp->isp_osinfo.fw = firmware_get(fwname); } -#else - if (isp_get_firmware_p) { - int device = (int) pci_get_device(dev); -#ifdef ISP_TARGET_MODE - (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); -#else - (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); -#endif + if (isp->isp_osinfo.fw == NULL) { + snprintf(fwname, sizeof (fwname), "isp_%04x", did); + isp->isp_osinfo.fw = firmware_get(fwname); + } + if (isp->isp_osinfo.fw != NULL) { + isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data; } -#endif /* * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER @@ -1077,43 +863,9 @@ isp_pci_attach(device_t dev) cmd &= ~PCIM_CMD_INTX_DISABLE; } -#ifdef WE_KNEW_WHAT_WE_WERE_DOING - if (IS_24XX(isp)) { - int reg; - - cmd &= ~PCIM_CMD_INTX_DISABLE; - - /* - * Is this a PCI-X card? If so, set max read byte count. - */ - if (pci_find_extcap(dev, PCIY_PCIX, ®) == 0) { - uint16_t pxcmd; - reg += 2; - - pxcmd = pci_read_config(dev, reg, 2); - pxcmd &= ~0xc; - pxcmd |= 0x8; - pci_write_config(dev, reg, 2, pxcmd); - } - - /* - * Is this a PCI Express card? If so, set max read byte count. - */ - if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { - uint16_t pectl; - - reg += 0x8; - pectl = pci_read_config(dev, reg, 2); - pectl &= ~0x7000; - pectl |= 0x4000; - pci_write_config(dev, reg, 2, pectl); - } - } -#else if (IS_24XX(isp)) { cmd &= ~PCIM_CMD_INTX_DISABLE; } -#endif pci_write_config(dev, PCIR_COMMAND, cmd, 2); @@ -1122,8 +874,7 @@ isp_pci_attach(device_t dev) */ data = pci_read_config(dev, PCIR_CACHELNSZ, 1); if (data == 0 || (linesz != PCI_DFLT_LNSZ && data != linesz)) { - isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d from %d", - linesz, data); + isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d from %d", linesz, data); data = linesz; pci_write_config(dev, PCIR_CACHELNSZ, data, 1); } @@ -1144,7 +895,12 @@ isp_pci_attach(device_t dev) data = pci_read_config(dev, PCIR_ROMADDR, 4); data &= ~1; pci_write_config(dev, PCIR_ROMADDR, data, 4); -#if __FreeBSD_version > 700025 + + /* + * Do MSI + * + * NB: MSI-X needs to be disabled for the 2432 (PCI-Express) + */ if (IS_24XX(isp) || IS_2322(isp)) { pcs->msicount = pci_msi_count(dev); if (pcs->msicount > 1) { @@ -1156,24 +912,17 @@ isp_pci_attach(device_t dev) iqd = 0; } } -#else - iqd = 0; -#endif - irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, - RF_ACTIVE | RF_SHAREABLE); + irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, RF_ACTIVE | RF_SHAREABLE); if (irq == NULL) { device_printf(dev, "could not allocate interrupt\n"); goto bad; } -#if __FreeBSD_version >= 500000 /* Make sure the lock is set up. */ mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); locksetup++; -#endif - if (isp_setup_intr(dev, irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, - &pcs->ih)) { + if (isp_setup_intr(dev, irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) { device_printf(dev, "could not setup interrupt\n"); goto bad; } @@ -1185,65 +934,52 @@ isp_pci_attach(device_t dev) isp->isp_port = pci_get_function(dev); } - if (IS_23XX(isp)) { - /* - * Can't tell if ROM will hang on 'ABOUT FIRMWARE' command. - */ - isp->isp_touched = 1; - } - /* * Make sure we're in reset state. */ ISP_LOCK(isp); - isp_reset(isp); + isp_reset(isp, 1); if (isp->isp_state != ISP_RESETSTATE) { ISP_UNLOCK(isp); goto bad; } isp_init(isp); - if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { - isp_uninit(isp); - ISP_UNLOCK(isp); - goto bad; - } - isp_attach(isp); - if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { - isp_uninit(isp); - ISP_UNLOCK(isp); - goto bad; + if (isp->isp_state == ISP_INITSTATE) { + isp->isp_state = ISP_RUNSTATE; } ISP_UNLOCK(isp); + if (isp_attach(isp)) { + ISP_LOCK(isp); + isp_uninit(isp); + ISP_UNLOCK(isp); + goto bad; + } return (0); bad: if (pcs && pcs->ih) { (void) bus_teardown_intr(dev, irq, pcs->ih); } -#if __FreeBSD_version >= 500000 if (locksetup && isp) { mtx_destroy(&isp->isp_osinfo.lock); } -#endif if (irq) { (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); } -#if __FreeBSD_version > 700025 if (pcs && pcs->msicount) { pci_release_msi(dev); } -#endif if (regs) { (void) bus_release_resource(dev, rtp, rgd, regs); } if (pcs) { if (pcs->pci_isp.isp_param) { -#ifdef ISP_FW_CRASH_DUMP - if (IS_FC(isp) && FCPARAM(isp)->isp_dump_data) { - free(FCPARAM(isp)->isp_dump_data, M_DEVBUF); - } -#endif free(pcs->pci_isp.isp_param, M_DEVBUF); + pcs->pci_isp.isp_param = NULL; + } + if (pcs->pci_isp.isp_osinfo.pc.ptr) { + free(pcs->pci_isp.isp_osinfo.pc.ptr, M_DEVBUF); + pcs->pci_isp.isp_osinfo.pc.ptr = NULL; } } return (ENXIO); @@ -1261,6 +997,7 @@ isp_pci_detach(device_t dev) } isp = (ispsoftc_t *) pcs; ISP_DISABLE_INTS(isp); + mtx_destroy(&isp->isp_osinfo.lock); return (0); } @@ -1278,7 +1015,7 @@ isp_pci_detach(device_t dev) bus_space_write_4(isp->isp_bus_tag, isp->isp_bus_handle, off, v) -static __inline int +static ISP_INLINE int isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp) { uint32_t val0, val1; @@ -1577,10 +1314,10 @@ isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff) case BIU2400_REQOUTP: case BIU2400_RSPINP: case BIU2400_RSPOUTP: - case BIU2400_PRI_RQINP: - case BIU2400_PRI_RSPINP: + case BIU2400_PRI_REQINP: + case BIU2400_PRI_REQOUTP: case BIU2400_ATIO_RSPINP: - case BIU2400_ATIO_REQINP: + case BIU2400_ATIO_RSPOUTP: case BIU2400_HCCR: case BIU2400_GPIOD: case BIU2400_GPIOE: @@ -1639,10 +1376,10 @@ isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val) case BIU2400_REQOUTP: case BIU2400_RSPINP: case BIU2400_RSPOUTP: - case BIU2400_PRI_RQINP: - case BIU2400_PRI_RSPINP: + case BIU2400_PRI_REQINP: + case BIU2400_PRI_REQOUTP: case BIU2400_ATIO_RSPINP: - case BIU2400_ATIO_REQINP: + case BIU2400_ATIO_RSPOUTP: case BIU2400_HCCR: case BIU2400_GPIOD: case BIU2400_GPIOE: @@ -1660,29 +1397,58 @@ isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val) struct imush { ispsoftc_t *isp; + caddr_t vbase; + int chan; int error; }; static void imc(void *, bus_dma_segment_t *, int, int); +static void imc1(void *, bus_dma_segment_t *, int, int); static void imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct imush *imushp = (struct imush *) arg; + if (error) { imushp->error = error; - } else { - ispsoftc_t *isp =imushp->isp; - bus_addr_t addr = segs->ds_addr; - - isp->isp_rquest_dma = addr; - addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - isp->isp_result_dma = addr; - if (IS_FC(isp)) { - addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); - FCPARAM(isp)->isp_scdma = addr; - } + return; } + if (nseg != 1) { + imushp->error = EINVAL; + return; + } + imushp->isp->isp_rquest = imushp->vbase; + imushp->isp->isp_rquest_dma = segs->ds_addr; + segs->ds_addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp)); + imushp->vbase += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp)); + imushp->isp->isp_result_dma = segs->ds_addr; + imushp->isp->isp_result = imushp->vbase; + +#ifdef ISP_TARGET_MODE + if (IS_24XX(imushp->isp)) { + segs->ds_addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp)); + imushp->vbase += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp)); + imushp->isp->isp_atioq_dma = segs->ds_addr; + imushp->isp->isp_atioq = imushp->vbase; + } +#endif +} + +static void +imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct imush *imushp = (struct imush *) arg; + if (error) { + imushp->error = error; + return; + } + if (nseg != 1) { + imushp->error = EINVAL; + return; + } + FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr; + FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase; } static int @@ -1690,7 +1456,7 @@ isp_pci_mbxdma(ispsoftc_t *isp) { caddr_t base; uint32_t len; - int i, error, ns; + int i, error, ns, cmap = 0; bus_size_t slim; /* segment size */ bus_addr_t llim; /* low limit of unavailable dma */ bus_addr_t hlim; /* high limit of unavailable dma */ @@ -1724,8 +1490,7 @@ isp_pci_mbxdma(ispsoftc_t *isp) } len = isp->isp_maxcmds * sizeof (struct isp_pcmd); - isp->isp_osinfo.pcmd_pool = - (struct isp_pcmd *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); + isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); if (isp->isp_osinfo.pcmd_pool == NULL) { isp_prt(isp, ISP_LOGERR, "cannot allocate pcmds"); ISP_LOCK(isp); @@ -1738,22 +1503,19 @@ isp_pci_mbxdma(ispsoftc_t *isp) #ifdef ISP_TARGET_MODE if (IS_SCSI(isp) && sizeof (bus_addr_t) > 4) { free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - ISP_LOCK(isp); isp_prt(isp, ISP_LOGERR, "we cannot do DAC for SPI cards yet"); + ISP_LOCK(isp); return (1); } #endif - if (isp_dma_tag_create(BUS_DMA_ROOTARG(ISP_PCD(isp)), 1, - slim, llim, hlim, NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, - slim, 0, &isp->isp_osinfo.dmat)) { + if (isp_dma_tag_create(BUS_DMA_ROOTARG(ISP_PCD(isp)), 1, slim, llim, hlim, NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0, &isp->isp_osinfo.dmat)) { free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); ISP_LOCK(isp); isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); return (1); } - len = sizeof (XS_T **) * isp->isp_maxcmds; isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); if (isp->isp_xflist == NULL) { @@ -1775,23 +1537,25 @@ isp_pci_mbxdma(ispsoftc_t *isp) #endif /* - * Allocate and map the request, result queues, plus FC scratch area. + * Allocate and map the request and result queues (and ATIO queue + * if we're a 2400 supporting target mode). */ len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); - if (IS_FC(isp)) { - len += ISP2100_SCRLEN; +#ifdef ISP_TARGET_MODE + if (IS_24XX(isp)) { + len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); } +#endif ns = (len / PAGE_SIZE) + 1; + /* - * Create a tag for the control spaces- force it to within 32 bits. + * Create a tag for the control spaces. We don't always need this + * to be 32 bits, but we do this for simplicity and speed's sake. */ - if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, - NULL, NULL, len, ns, slim, 0, &isp->isp_cdmat)) { - isp_prt(isp, ISP_LOGERR, - "cannot create a dma tag for control spaces"); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, len, ns, slim, 0, &isp->isp_osinfo.cdmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces"); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); free(isp->isp_xflist, M_DEVBUF); #ifdef ISP_TARGET_MODE @@ -1801,11 +1565,9 @@ isp_pci_mbxdma(ispsoftc_t *isp) return (1); } - if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, - &isp->isp_cdmap) != 0) { - isp_prt(isp, ISP_LOGERR, - "cannot allocate %d bytes of CCB memory", len); - bus_dma_tag_destroy(isp->isp_cdmat); + if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT, &isp->isp_osinfo.cdmap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len); + bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); free(isp->isp_xflist, M_DEVBUF); #ifdef ISP_TARGET_MODE @@ -1815,19 +1577,51 @@ isp_pci_mbxdma(ispsoftc_t *isp) return (1); } + im.isp = isp; + im.chan = 0; + im.vbase = base; + im.error = 0; + + bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0); + if (im.error) { + isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error); + goto bad; + } + + if (IS_FC(isp)) { + for (cmap = 0; cmap < isp->isp_nchan; cmap++) { + struct isp_fc *fc = ISP_FC_PC(isp, cmap); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ISP_FC_SCRLEN, 1, slim, 0, &fc->tdmat)) { + goto bad; + } + if (bus_dmamem_alloc(fc->tdmat, (void **)&base, BUS_DMA_NOWAIT, &fc->tdmap) != 0) { + bus_dma_tag_destroy(fc->tdmat); + goto bad; + } + im.isp = isp; + im.chan = cmap; + im.vbase = base; + im.error = 0; + bus_dmamap_load(fc->tdmat, fc->tdmap, base, ISP_FC_SCRLEN, imc1, &im, 0); + if (im.error) { + bus_dmamem_free(fc->tdmat, base, fc->tdmap); + bus_dma_tag_destroy(fc->tdmat); + goto bad; + } + } + } + for (i = 0; i < isp->isp_maxcmds; i++) { struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i]; error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap); if (error) { - isp_prt(isp, ISP_LOGERR, - "error %d creating per-cmd DMA maps", error); + isp_prt(isp, ISP_LOGERR, "error %d creating per-cmd DMA maps", error); while (--i >= 0) { - bus_dmamap_destroy(isp->isp_osinfo.dmat, - isp->isp_osinfo.pcmd_pool[i].dmap); + bus_dmamap_destroy(isp->isp_osinfo.dmat, isp->isp_osinfo.pcmd_pool[i].dmap); } goto bad; } - isp_callout_init(&pcmd->wdog); + callout_init_mtx(&pcmd->wdog, &isp->isp_osinfo.lock, 0); if (i == isp->isp_maxcmds-1) { pcmd->next = NULL; } else { @@ -1835,29 +1629,17 @@ isp_pci_mbxdma(ispsoftc_t *isp) } } isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0]; - - im.isp = isp; - im.error = 0; - bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); - if (im.error) { - isp_prt(isp, ISP_LOGERR, - "error %d loading dma map for control areas", im.error); - goto bad; - } - - isp->isp_rquest = base; - base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - isp->isp_result = base; - if (IS_FC(isp)) { - base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); - FCPARAM(isp)->isp_scratch = base; - } ISP_LOCK(isp); return (0); bad: - bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); - bus_dma_tag_destroy(isp->isp_cdmat); + while (--cmap >= 0) { + struct isp_fc *fc = ISP_FC_PC(isp, cmap); + bus_dmamem_free(fc->tdmat, base, fc->tdmap); + bus_dma_tag_destroy(fc->tdmat); + } + bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); + bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_xflist, M_DEVBUF); #ifdef ISP_TARGET_MODE free(isp->isp_tgtlist, M_DEVBUF); @@ -1871,721 +1653,91 @@ isp_pci_mbxdma(ispsoftc_t *isp) typedef struct { ispsoftc_t *isp; void *cmd_token; - void *rq; - uint32_t *nxtip; - uint32_t optr; + void *rq; /* original request */ int error; + bus_size_t mapsize; } mush_t; #define MUSHERR_NOQENTRIES -2 #ifdef ISP_TARGET_MODE -/* - * We need to handle DMA for target mode differently from initiator mode. - * - * DMA mapping and construction and submission of CTIO Request Entries - * and rendevous for completion are very tightly coupled because we start - * out by knowing (per platform) how much data we have to move, but we - * don't know, up front, how many DMA mapping segments will have to be used - * cover that data, so we don't know how many CTIO Request Entries we - * will end up using. Further, for performance reasons we may want to - * (on the last CTIO for Fibre Channel), send status too (if all went well). - * - * The standard vector still goes through isp_pci_dmasetup, but the callback - * for the DMA mapping routines comes here instead with the whole transfer - * mapped and a pointer to a partially filled in already allocated request - * queue entry. We finish the job. - */ -static void tdma_mk(void *, bus_dma_segment_t *, int, int); -static void tdma_mkfc(void *, bus_dma_segment_t *, int, int); - -#define STATUS_WITH_DATA 1 +static void tdma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int); +static void tdma2(void *, bus_dma_segment_t *, int, int); static void -tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +tdma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error) +{ + mush_t *mp; + mp = (mush_t *)arg; + mp->mapsize = mapsize; + tdma2(arg, dm_segs, nseg, error); +} + +static void +tdma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) { mush_t *mp; - struct ccb_scsiio *csio; ispsoftc_t *isp; - ct_entry_t *cto, *qe; - uint8_t scsi_status; - uint32_t curi, nxti, handle; - uint32_t sflags; - int32_t resid; - int nth_ctio, nctios, send_status; + struct ccb_scsiio *csio; + isp_ddir_t ddir; + ispreq_t *rq; mp = (mush_t *) arg; if (error) { mp->error = error; return; } - - isp = mp->isp; csio = mp->cmd_token; - cto = mp->rq; - curi = isp->isp_reqidx; - qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); - - cto->ct_xfrlen = 0; - cto->ct_seg_count = 0; - cto->ct_header.rqs_entry_count = 1; - MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); - - if (nseg == 0) { - cto->ct_header.rqs_seqno = 1; - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d", - cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, - cto->ct_tag_val, cto->ct_flags, cto->ct_status, - cto->ct_scsi_status, cto->ct_resid); - ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); - isp_put_ctio(isp, cto, qe); - return; - } - - nctios = nseg / ISP_RQDSEG; - if (nseg % ISP_RQDSEG) { - nctios++; - } - - /* - * Save syshandle, and potentially any SCSI status, which we'll - * reinsert on the last CTIO we're going to send. - */ - - handle = cto->ct_syshandle; - cto->ct_syshandle = 0; - cto->ct_header.rqs_seqno = 0; - send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; - - if (send_status) { - sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); - cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); - /* - * Preserve residual. - */ - resid = cto->ct_resid; - - /* - * Save actual SCSI status. - */ - scsi_status = cto->ct_scsi_status; - -#ifndef STATUS_WITH_DATA - sflags |= CT_NO_DATA; - /* - * We can't do a status at the same time as a data CTIO, so - * we need to synthesize an extra CTIO at this level. - */ - nctios++; -#endif - } else { - sflags = scsi_status = resid = 0; - } - - cto->ct_resid = 0; - cto->ct_scsi_status = 0; - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); - } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); - } - - nxti = *mp->nxtip; - - for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { - int seglim; - - seglim = nseg; - if (seglim) { - int seg; - - if (seglim > ISP_RQDSEG) - seglim = ISP_RQDSEG; - - for (seg = 0; seg < seglim; seg++, nseg--) { - /* - * Unlike normal initiator commands, we don't - * do any swizzling here. - */ - cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; - cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; - cto->ct_xfrlen += dm_segs->ds_len; - dm_segs++; + isp = mp->isp; + rq = mp->rq; + if (nseg) { + if (sizeof (bus_addr_t) > 4) { + if (nseg >= ISP_NSEG64_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX); + mp->error = EFAULT; + return; + } + if (rq->req_header.rqs_entry_type == RQSTYPE_CTIO2) { + rq->req_header.rqs_entry_type = RQSTYPE_CTIO3; } - cto->ct_seg_count = seg; } else { - /* - * This case should only happen when we're sending an - * extra CTIO with final status. - */ - if (send_status == 0) { - isp_prt(isp, ISP_LOGWARN, - "tdma_mk ran out of segments"); - mp->error = EINVAL; + if (nseg >= ISP_NSEG_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX); + mp->error = EFAULT; return; } } - - /* - * At this point, the fields ct_lun, ct_iid, ct_tagval, - * ct_tagtype, and ct_timeout have been carried over - * unchanged from what our caller had set. - * - * The dataseg fields and the seg_count fields we just got - * through setting. The data direction we've preserved all - * along and only clear it if we're now sending status. - */ - - if (nth_ctio == nctios - 1) { - /* - * We're the last in a sequence of CTIOs, so mark - * this CTIO and save the handle to the CCB such that - * when this CTIO completes we can free dma resources - * and do whatever else we need to do to finish the - * rest of the command. We *don't* give this to the - * firmware to work on- the caller will do that. - */ - - cto->ct_syshandle = handle; - cto->ct_header.rqs_seqno = 1; - - if (send_status) { - cto->ct_scsi_status = scsi_status; - cto->ct_flags |= sflags; - cto->ct_resid = resid; - } - if (send_status) { - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO[%x] lun%d iid %d tag %x ct_flags %x " - "scsi status %x resid %d", - cto->ct_fwhandle, csio->ccb_h.target_lun, - cto->ct_iid, cto->ct_tag_val, cto->ct_flags, - cto->ct_scsi_status, cto->ct_resid); - } else { - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x", - cto->ct_fwhandle, csio->ccb_h.target_lun, - cto->ct_iid, cto->ct_tag_val, - cto->ct_flags); - } - isp_put_ctio(isp, cto, qe); - ISP_TDQE(isp, "last tdma_mk", curi, cto); - if (nctios > 1) { - MEMORYBARRIER(isp, SYNC_REQUEST, - curi, QENTRY_LEN); - } + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); + ddir = ISP_TO_DEVICE; + } else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); + ddir = ISP_FROM_DEVICE; } else { - ct_entry_t *oqe = qe; - - /* - * Make sure syshandle fields are clean - */ - cto->ct_syshandle = 0; - cto->ct_header.rqs_seqno = 0; - - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO[%x] lun%d for ID%d ct_flags 0x%x", - cto->ct_fwhandle, csio->ccb_h.target_lun, - cto->ct_iid, cto->ct_flags); - - /* - * Get a new CTIO - */ - qe = (ct_entry_t *) - ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGTDEBUG0, - "Queue Overflow in tdma_mk"); - mp->error = MUSHERR_NOQENTRIES; - return; - } - - /* - * Now that we're done with the old CTIO, - * flush it out to the request queue. - */ - ISP_TDQE(isp, "dma_tgt_fc", curi, cto); - isp_put_ctio(isp, cto, oqe); - if (nth_ctio != 0) { - MEMORYBARRIER(isp, SYNC_REQUEST, curi, - QENTRY_LEN); - } - curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); - - /* - * Reset some fields in the CTIO so we can reuse - * for the next one we'll flush to the request - * queue. - */ - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; - cto->ct_header.rqs_entry_count = 1; - cto->ct_header.rqs_flags = 0; - cto->ct_status = 0; - cto->ct_scsi_status = 0; - cto->ct_xfrlen = 0; - cto->ct_resid = 0; - cto->ct_seg_count = 0; - MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); + ddir = ISP_NOXFR; } - } - *mp->nxtip = nxti; -} - -/* - * We don't have to do multiple CTIOs here. Instead, we can just do - * continuation segments as needed. This greatly simplifies the code - * improves performance. - */ - -static void -tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) -{ - mush_t *mp; - struct ccb_scsiio *csio; - ispsoftc_t *isp; - ct2_entry_t *cto, *qe; - uint32_t curi, nxti; - ispds_t *ds; - ispds64_t *ds64; - int segcnt, seglim; - - mp = (mush_t *) arg; - if (error) { - mp->error = error; - return; - } - - isp = mp->isp; - csio = mp->cmd_token; - cto = mp->rq; - - curi = isp->isp_reqidx; - qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); - - if (nseg == 0) { - if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { - isp_prt(isp, ISP_LOGWARN, - "dma2_tgt_fc, a status CTIO2 without MODE1 " - "set (0x%x)", cto->ct_flags); - mp->error = EINVAL; - return; - } - /* - * We preserve ct_lun, ct_iid, ct_rxid. We set the data - * flags to NO DATA and clear relative offset flags. - * We preserve the ct_resid and the response area. - */ - cto->ct_header.rqs_seqno = 1; - cto->ct_seg_count = 0; - cto->ct_reloff = 0; - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " - "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, - cto->ct_iid, cto->ct_flags, cto->ct_status, - cto->rsp.m1.ct_scsi_status, cto->ct_resid); - if (FCPARAM(isp)->isp_2klogin) { - isp_put_ctio2e(isp, - (ct2e_entry_t *)cto, (ct2e_entry_t *)qe); - } else { - isp_put_ctio2(isp, cto, qe); - } - ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe); - return; - } - - if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { - isp_prt(isp, ISP_LOGERR, - "dma2_tgt_fc, a data CTIO2 without MODE0 set " - "(0x%x)", cto->ct_flags); - mp->error = EINVAL; - return; - } - - - nxti = *mp->nxtip; - - /* - * Check to see if we need to DAC addressing or not. - * - * Any address that's over the 4GB boundary causes this - * to happen. - */ - segcnt = nseg; - if (sizeof (bus_addr_t) > 4) { - for (segcnt = 0; segcnt < nseg; segcnt++) { - uint64_t addr = dm_segs[segcnt].ds_addr; - if (addr >= 0x100000000LL) { - break; - } - } - } - if (segcnt != nseg) { - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - seglim = ISP_RQDSEG_T3; - ds64 = &cto->rsp.m0.u.ct_dataseg64[0]; - ds = NULL; } else { - seglim = ISP_RQDSEG_T2; - ds64 = NULL; - ds = &cto->rsp.m0.u.ct_dataseg[0]; - } - cto->ct_seg_count = 0; - - /* - * Set up the CTIO2 data segments. - */ - for (segcnt = 0; cto->ct_seg_count < seglim && segcnt < nseg; - cto->ct_seg_count++, segcnt++) { - if (ds64) { - ds64->ds_basehi = - ((uint64_t) (dm_segs[segcnt].ds_addr) >> 32); - ds64->ds_base = dm_segs[segcnt].ds_addr; - ds64->ds_count = dm_segs[segcnt].ds_len; - ds64++; - } else { - ds->ds_base = dm_segs[segcnt].ds_addr; - ds->ds_count = dm_segs[segcnt].ds_len; - ds++; - } - cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; -#if __FreeBSD_version < 500000 - isp_prt(isp, ISP_LOGTDEBUG1, - "isp_send_ctio2: ent0[%d]0x%llx:%llu", - cto->ct_seg_count, (uint64_t)dm_segs[segcnt].ds_addr, - (uint64_t)dm_segs[segcnt].ds_len); -#else - isp_prt(isp, ISP_LOGTDEBUG1, - "isp_send_ctio2: ent0[%d]0x%jx:%ju", - cto->ct_seg_count, (uintmax_t)dm_segs[segcnt].ds_addr, - (uintmax_t)dm_segs[segcnt].ds_len); -#endif + dm_segs = NULL; + nseg = 0; + ddir = ISP_NOXFR; } - while (segcnt < nseg) { - uint32_t curip; - int seg; - ispcontreq_t local, *crq = &local, *qep; - - qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - curip = nxti; - nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGTDEBUG0, - "tdma_mkfc: request queue overflow"); - mp->error = MUSHERR_NOQENTRIES; - return; - } - cto->ct_header.rqs_entry_count++; - MEMZERO((void *)crq, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - if (cto->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { - seglim = ISP_CDSEG64; - ds = NULL; - ds64 = &((ispcontreq64_t *)crq)->req_dataseg[0]; - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - } else { - seglim = ISP_CDSEG; - ds = &crq->req_dataseg[0]; - ds64 = NULL; - crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; - } - for (seg = 0; segcnt < nseg && seg < seglim; - segcnt++, seg++) { - if (ds64) { - ds64->ds_basehi = - ((uint64_t) (dm_segs[segcnt].ds_addr) >> 32); - ds64->ds_base = dm_segs[segcnt].ds_addr; - ds64->ds_count = dm_segs[segcnt].ds_len; - ds64++; - } else { - ds->ds_base = dm_segs[segcnt].ds_addr; - ds->ds_count = dm_segs[segcnt].ds_len; - ds++; - } -#if __FreeBSD_version < 500000 - isp_prt(isp, ISP_LOGTDEBUG1, - "isp_send_ctio2: ent%d[%d]%llx:%llu", - cto->ct_header.rqs_entry_count-1, seg, - (uint64_t)dm_segs[segcnt].ds_addr, - (uint64_t)dm_segs[segcnt].ds_len); -#else - isp_prt(isp, ISP_LOGTDEBUG1, - "isp_send_ctio2: ent%d[%d]%jx:%ju", - cto->ct_header.rqs_entry_count-1, seg, - (uintmax_t)dm_segs[segcnt].ds_addr, - (uintmax_t)dm_segs[segcnt].ds_len); -#endif - cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; - cto->ct_seg_count++; - } - MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); - isp_put_cont_req(isp, crq, qep); - ISP_TDQE(isp, "cont entry", curi, qep); + if (isp_send_tgt_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir, &csio->sense_data, csio->sense_len) != CMD_QUEUED) { + mp->error = MUSHERR_NOQENTRIES; } - - /* - * No do final twiddling for the CTIO itself. - */ - cto->ct_header.rqs_seqno = 1; - isp_prt(isp, ISP_LOGTDEBUG1, - "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d", - cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid, - cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, - cto->ct_resid); - if (FCPARAM(isp)->isp_2klogin) { - isp_put_ctio2e(isp, (ct2e_entry_t *)cto, (ct2e_entry_t *)qe); - } else { - isp_put_ctio2(isp, cto, qe); - } - ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe); - *mp->nxtip = nxti; } #endif -static void dma_2400(void *, bus_dma_segment_t *, int, int); -static void dma2_a64(void *, bus_dma_segment_t *, int, int); +static void dma2_2(void *, bus_dma_segment_t *, int, bus_size_t, int); static void dma2(void *, bus_dma_segment_t *, int, int); static void -dma_2400(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +dma2_2(void *arg, bus_dma_segment_t *dm_segs, int nseg, bus_size_t mapsize, int error) { mush_t *mp; - ispsoftc_t *isp; - struct ccb_scsiio *csio; - bus_dma_segment_t *eseg; - ispreqt7_t *rq; - int seglim, datalen; - uint32_t nxti; - - mp = (mush_t *) arg; - if (error) { - mp->error = error; - return; - } - - if (nseg < 1) { - isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); - mp->error = EFAULT; - return; - } - - csio = mp->cmd_token; - isp = mp->isp; - rq = mp->rq; - nxti = *mp->nxtip; - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); - } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); - } - datalen = XS_XFRLEN(csio); - - /* - * We're passed an initial partially filled in entry that - * has most fields filled in except for data transfer - * related values. - * - * Our job is to fill in the initial request queue entry and - * then to start allocating and filling in continuation entries - * until we've covered the entire transfer. - */ - - rq->req_header.rqs_entry_type = RQSTYPE_T7RQS; - rq->req_dl = datalen; - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - rq->req_alen_datadir = 0x2; - } else { - rq->req_alen_datadir = 0x1; - } - - eseg = dm_segs + nseg; - - rq->req_dataseg.ds_base = DMA_LO32(dm_segs->ds_addr); - rq->req_dataseg.ds_basehi = DMA_HI32(dm_segs->ds_addr); - rq->req_dataseg.ds_count = dm_segs->ds_len; - - datalen -= dm_segs->ds_len; - - dm_segs++; - rq->req_seg_count++; - - while (datalen > 0 && dm_segs != eseg) { - uint32_t onxti; - ispcontreq64_t local, *crq = &local, *cqe; - - cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - onxti = nxti; - nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); - mp->error = MUSHERR_NOQENTRIES; - return; - } - rq->req_header.rqs_entry_count++; - MEMZERO((void *)crq, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - - seglim = 0; - while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) { - crq->req_dataseg[seglim].ds_base = - DMA_LO32(dm_segs->ds_addr); - crq->req_dataseg[seglim].ds_basehi = - DMA_HI32(dm_segs->ds_addr); - crq->req_dataseg[seglim].ds_count = - dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - seglim++; - datalen -= dm_segs->ds_len; - } - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq); - } - isp_put_cont64_req(isp, crq, cqe); - MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); - } - *mp->nxtip = nxti; -} - -static void -dma2_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) -{ - mush_t *mp; - ispsoftc_t *isp; - struct ccb_scsiio *csio; - bus_dma_segment_t *eseg; - ispreq64_t *rq; - int seglim, datalen; - uint32_t nxti; - - mp = (mush_t *) arg; - if (error) { - mp->error = error; - return; - } - - if (nseg < 1) { - isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); - mp->error = EFAULT; - return; - } - csio = mp->cmd_token; - isp = mp->isp; - rq = mp->rq; - nxti = *mp->nxtip; - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); - } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); - } - datalen = XS_XFRLEN(csio); - - /* - * We're passed an initial partially filled in entry that - * has most fields filled in except for data transfer - * related values. - * - * Our job is to fill in the initial request queue entry and - * then to start allocating and filling in continuation entries - * until we've covered the entire transfer. - */ - - if (IS_FC(isp)) { - rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; - seglim = ISP_RQDSEG_T3; - ((ispreqt3_t *)rq)->req_totalcnt = datalen; - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_IN; - } else { - ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_OUT; - } - } else { - rq->req_header.rqs_entry_type = RQSTYPE_A64; - if (csio->cdb_len > 12) { - seglim = 0; - } else { - seglim = ISP_RQDSEG_A64; - } - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - rq->req_flags |= REQFLAG_DATA_IN; - } else { - rq->req_flags |= REQFLAG_DATA_OUT; - } - } - - eseg = dm_segs + nseg; - - while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { - if (IS_FC(isp)) { - ispreqt3_t *rq3 = (ispreqt3_t *)rq; - rq3->req_dataseg[rq3->req_seg_count].ds_base = - DMA_LO32(dm_segs->ds_addr); - rq3->req_dataseg[rq3->req_seg_count].ds_basehi = - DMA_HI32(dm_segs->ds_addr); - rq3->req_dataseg[rq3->req_seg_count].ds_count = - dm_segs->ds_len; - } else { - rq->req_dataseg[rq->req_seg_count].ds_base = - DMA_LO32(dm_segs->ds_addr); - rq->req_dataseg[rq->req_seg_count].ds_basehi = - DMA_HI32(dm_segs->ds_addr); - rq->req_dataseg[rq->req_seg_count].ds_count = - dm_segs->ds_len; - } - datalen -= dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - } - - while (datalen > 0 && dm_segs != eseg) { - uint32_t onxti; - ispcontreq64_t local, *crq = &local, *cqe; - - cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - onxti = nxti; - nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); - mp->error = MUSHERR_NOQENTRIES; - return; - } - rq->req_header.rqs_entry_count++; - MEMZERO((void *)crq, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - - seglim = 0; - while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) { - crq->req_dataseg[seglim].ds_base = - DMA_LO32(dm_segs->ds_addr); - crq->req_dataseg[seglim].ds_basehi = - DMA_HI32(dm_segs->ds_addr); - crq->req_dataseg[seglim].ds_count = - dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - seglim++; - datalen -= dm_segs->ds_len; - } - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq); - } - isp_put_cont64_req(isp, crq, cqe); - MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); - } - *mp->nxtip = nxti; + mp = (mush_t *)arg; + mp->mapsize = mapsize; + dma2(arg, dm_segs, nseg, error); } static void @@ -2594,206 +1746,99 @@ dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) mush_t *mp; ispsoftc_t *isp; struct ccb_scsiio *csio; - bus_dma_segment_t *eseg; + isp_ddir_t ddir; ispreq_t *rq; - int seglim, datalen; - uint32_t nxti; mp = (mush_t *) arg; if (error) { mp->error = error; return; } - - if (nseg < 1) { - isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); - mp->error = EFAULT; - return; - } csio = mp->cmd_token; isp = mp->isp; rq = mp->rq; - nxti = *mp->nxtip; - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); - } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); - } - - datalen = XS_XFRLEN(csio); - - /* - * We're passed an initial partially filled in entry that - * has most fields filled in except for data transfer - * related values. - * - * Our job is to fill in the initial request queue entry and - * then to start allocating and filling in continuation entries - * until we've covered the entire transfer. - */ - - if (IS_FC(isp)) { - seglim = ISP_RQDSEG_T2; - ((ispreqt2_t *)rq)->req_totalcnt = datalen; - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; + if (nseg) { + if (sizeof (bus_addr_t) > 4) { + if (nseg >= ISP_NSEG64_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX); + mp->error = EFAULT; + return; + } + if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) { + rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; + } else if (rq->req_header.rqs_entry_type == RQSTYPE_REQUEST) { + rq->req_header.rqs_entry_type = RQSTYPE_A64; + } } else { - ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; - } - } else { - if (csio->cdb_len > 12) { - seglim = 0; - } else { - seglim = ISP_RQDSEG; + if (nseg >= ISP_NSEG_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX); + mp->error = EFAULT; + return; + } } if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - rq->req_flags |= REQFLAG_DATA_IN; + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); + ddir = ISP_FROM_DEVICE; + } else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); + ddir = ISP_TO_DEVICE; } else { - rq->req_flags |= REQFLAG_DATA_OUT; + ddir = ISP_NOXFR; } + } else { + dm_segs = NULL; + nseg = 0; + ddir = ISP_NOXFR; } - eseg = dm_segs + nseg; - - while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { - if (IS_FC(isp)) { - ispreqt2_t *rq2 = (ispreqt2_t *)rq; - rq2->req_dataseg[rq2->req_seg_count].ds_base = - DMA_LO32(dm_segs->ds_addr); - rq2->req_dataseg[rq2->req_seg_count].ds_count = - dm_segs->ds_len; - } else { - rq->req_dataseg[rq->req_seg_count].ds_base = - DMA_LO32(dm_segs->ds_addr); - rq->req_dataseg[rq->req_seg_count].ds_count = - dm_segs->ds_len; - } - datalen -= dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; + if (isp_send_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir) != CMD_QUEUED) { + mp->error = MUSHERR_NOQENTRIES; } - - while (datalen > 0 && dm_segs != eseg) { - uint32_t onxti; - ispcontreq_t local, *crq = &local, *cqe; - - cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - onxti = nxti; - nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); - mp->error = MUSHERR_NOQENTRIES; - return; - } - rq->req_header.rqs_entry_count++; - MEMZERO((void *)crq, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; - - seglim = 0; - while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { - crq->req_dataseg[seglim].ds_base = - DMA_LO32(dm_segs->ds_addr); - crq->req_dataseg[seglim].ds_count = - dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - seglim++; - datalen -= dm_segs->ds_len; - } - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq); - } - isp_put_cont_req(isp, crq, cqe); - MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); - } - *mp->nxtip = nxti; } -/* - */ static int -isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, - uint32_t *nxtip, uint32_t optr) +isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff) { - ispreq_t *qep; mush_t mush, *mp; void (*eptr)(void *, bus_dma_segment_t *, int, int); + void (*eptr2)(void *, bus_dma_segment_t *, int, bus_size_t, int); - qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); -#ifdef ISP_TARGET_MODE - if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { - if (IS_FC(isp)) { - eptr = tdma_mkfc; - } else { - eptr = tdma_mk; - } - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || - (csio->dxfer_len == 0)) { - mp = &mush; - mp->isp = isp; - mp->cmd_token = csio; - mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */ - mp->nxtip = nxtip; - mp->optr = optr; - mp->error = 0; - (*eptr)(mp, NULL, 0, 0); - goto mbxsync; - } - } else -#endif - if (IS_24XX(isp)) { - eptr = dma_2400; - } else if (sizeof (bus_addr_t) > 4) { - eptr = dma2_a64; - } else { - eptr = dma2; - } - - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || - (csio->dxfer_len == 0)) { - rq->req_seg_count = 1; - goto mbxsync; - } - - /* - * Do a virtual grapevine step to collect info for - * the callback dma allocation that we have to use... - */ mp = &mush; mp->isp = isp; mp->cmd_token = csio; - mp->rq = rq; - mp->nxtip = nxtip; - mp->optr = optr; + mp->rq = ff; mp->error = 0; + mp->mapsize = 0; - if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { +#ifdef ISP_TARGET_MODE + if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { + eptr = tdma2; + eptr2 = tdma2_2; + } else +#endif + { + eptr = dma2; + eptr2 = dma2_2; + } + + + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || (csio->dxfer_len == 0)) { + (*eptr)(mp, NULL, 0, 0); + } else if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { int error; -#if __FreeBSD_version < 500000 - int s = splsoftvm(); -#endif - error = bus_dmamap_load(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, csio->data_ptr, - csio->dxfer_len, eptr, mp, 0); -#if __FreeBSD_version < 500000 - splx(s); + error = bus_dmamap_load(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, csio->data_ptr, csio->dxfer_len, eptr, mp, 0); +#if 0 + xpt_print(csio->ccb_h.path, "%s: bus_dmamap_load " "ptr %p len %d returned %d\n", __func__, csio->data_ptr, csio->dxfer_len, error); #endif + if (error == EINPROGRESS) { - bus_dmamap_unload(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap); + bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); mp->error = EINVAL; - isp_prt(isp, ISP_LOGERR, - "deferred dma allocation not supported"); + isp_prt(isp, ISP_LOGERR, "deferred dma allocation not supported"); } else if (error && mp->error == 0) { #ifdef DIAGNOSTIC - isp_prt(isp, ISP_LOGERR, - "error %d in dma mapping code", error); + isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error); #endif mp->error = error; } @@ -2808,13 +1853,34 @@ isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, struct bus_dma_segment *segs; if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { - isp_prt(isp, ISP_LOGERR, - "Physical segment pointers unsupported"); + isp_prt(isp, ISP_LOGERR, "Physical segment pointers unsupported"); mp->error = EINVAL; } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { - isp_prt(isp, ISP_LOGERR, - "Virtual segment addresses unsupported"); - mp->error = EINVAL; + struct uio sguio; + int error; + + /* + * We're taking advantage of the fact that + * the pointer/length sizes and layout of the iovec + * structure are the same as the bus_dma_segment + * structure. This might be a little dangerous, + * but only if they change the structures, which + * seems unlikely. + */ + KASSERT((sizeof (sguio.uio_iov) == sizeof (csio->data_ptr) && + sizeof (sguio.uio_iovcnt) >= sizeof (csio->sglist_cnt) && + sizeof (sguio.uio_resid) >= sizeof (csio->dxfer_len)), ("Ken's assumption failed")); + sguio.uio_iov = (struct iovec *)csio->data_ptr; + sguio.uio_iovcnt = csio->sglist_cnt; + sguio.uio_resid = csio->dxfer_len; + sguio.uio_segflg = UIO_SYSSPACE; + + error = bus_dmamap_load_uio(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, &sguio, eptr2, mp, 0); + + if (error != 0 && mp->error == 0) { + isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error); + mp->error = error; + } } else { /* Just use the segments provided */ segs = (struct bus_dma_segment *) csio->data_ptr; @@ -2834,41 +1900,6 @@ isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, } return (retval); } -mbxsync: - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "Request Queue Entry", QENTRY_LEN, rq); - } - switch (rq->req_header.rqs_entry_type) { - case RQSTYPE_REQUEST: - isp_put_request(isp, rq, qep); - break; - case RQSTYPE_CMDONLY: - isp_put_extended_request(isp, (ispextreq_t *)rq, - (ispextreq_t *)qep); - break; - case RQSTYPE_T2RQS: - if (FCPARAM(isp)->isp_2klogin) { - isp_put_request_t2e(isp, - (ispreqt2e_t *) rq, (ispreqt2e_t *) qep); - } else { - isp_put_request_t2(isp, - (ispreqt2_t *) rq, (ispreqt2_t *) qep); - } - break; - case RQSTYPE_T3RQS: - if (FCPARAM(isp)->isp_2klogin) { - isp_put_request_t3e(isp, - (ispreqt3e_t *) rq, (ispreqt3e_t *) qep); - break; - } - /* FALLTHROUGH */ - case RQSTYPE_A64: - isp_put_request_t3(isp, (ispreqt3_t *) rq, (ispreqt3_t *) qep); - break; - case RQSTYPE_T7RQS: - isp_put_request_t7(isp, (ispreqt7_t *) rq, (ispreqt7_t *) qep); - break; - } return (CMD_QUEUED); } diff --git a/sys/dev/isp/isp_sbus.c b/sys/dev/isp/isp_sbus.c index 839d7eb5f461..af7cb88d602e 100644 --- a/sys/dev/isp/isp_sbus.c +++ b/sys/dev/isp/isp_sbus.c @@ -33,10 +33,8 @@ __FBSDID("$FreeBSD$"); #include #include -#if __FreeBSD_version >= 700000 #include #include -#endif #include #include #include @@ -51,15 +49,12 @@ __FBSDID("$FreeBSD$"); #include -static uint32_t -isp_sbus_rd_reg(ispsoftc_t *, int); -static void -isp_sbus_wr_reg(ispsoftc_t *, int, uint32_t); -static int -isp_sbus_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); +static uint32_t isp_sbus_rd_reg(ispsoftc_t *, int); +static void isp_sbus_wr_reg(ispsoftc_t *, int, uint32_t); +static int isp_sbus_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); static int isp_sbus_mbxdma(ispsoftc_t *); -static int -isp_sbus_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); +static int isp_sbus_dmasetup(ispsoftc_t *, XS_T *, void *); + static void isp_sbus_reset0(ispsoftc_t *); static void isp_sbus_reset1(ispsoftc_t *); @@ -91,6 +86,7 @@ struct isp_sbussoftc { void * ih; int16_t sbus_poff[_NREG_BLKS]; sdparam sbus_param; + struct isp_spi sbus_spi; struct ispmdvec sbus_mdvec; struct resource * sbus_ires; }; @@ -108,9 +104,6 @@ static driver_t isp_sbus_driver = { }; static devclass_t isp_devclass; DRIVER_MODULE(isp, sbus, isp_sbus_driver, isp_devclass, 0, 0); -#if __FreeBSD_version < 700000 -extern ispfwfunc *isp_get_firmware_p; -#endif static int isp_sbus_probe(device_t dev) @@ -140,7 +133,7 @@ static int isp_sbus_attach(device_t dev) { struct resource *regs; - int tval, iqd, isp_debug, role, rid, ispburst; + int tval, iqd, isp_debug, role, rid, ispburst, default_id; struct isp_sbussoftc *sbs; ispsoftc_t *isp = NULL; int locksetup = 0; @@ -165,11 +158,7 @@ isp_sbus_attach(device_t dev) ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) { device_printf(dev, "setting role to 0x%x\n", role); } else { -#ifdef ISP_TARGET_MODE - role = ISP_ROLE_INITIATOR|ISP_ROLE_TARGET; -#else role = ISP_DEFAULT_ROLES; -#endif } sbs = malloc(sizeof (*sbs), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -202,9 +191,9 @@ isp_sbus_attach(device_t dev) isp->isp_bustype = ISP_BT_SBUS; isp->isp_type = ISP_HA_SCSI_UNKNOWN; isp->isp_param = &sbs->sbus_param; + isp->isp_osinfo.pc.ptr = &sbs->sbus_spi; isp->isp_revision = 0; /* XXX */ - isp->isp_role = role; - isp->isp_dev = dev; + ISP_SET_PC(isp, 0, role, role); /* * Get the clock frequency and convert it from HZ to MHz, @@ -246,11 +235,10 @@ isp_sbus_attach(device_t dev) */ if (strcmp("PTI,ptisp", ofw_bus_get_name(dev)) == 0 || strcmp("ptisp", ofw_bus_get_name(dev)) == 0) { - SDPARAM(isp)->isp_ptisp = 1; + SDPARAM(isp, 0)->isp_ptisp = 1; } -#if __FreeBSD_version >= 700000 isp->isp_osinfo.fw = firmware_get("isp_1000"); if (isp->isp_osinfo.fw) { union { @@ -260,14 +248,6 @@ isp_sbus_attach(device_t dev) stupid.cp = isp->isp_osinfo.fw->data; isp->isp_mdvec->dv_ispfw = stupid.sp; } -#else - /* - * Try and find firmware for this device. - */ - if (isp_get_firmware_p) { - (*isp_get_firmware_p)(0, 0, 0x1000, &sbs->sbus_mdvec.dv_ispfw); - } -#endif tval = 0; if (resource_int_value(device_get_name(dev), device_get_unit(dev), @@ -275,19 +255,20 @@ isp_sbus_attach(device_t dev) isp->isp_confopts |= ISP_CFG_NORELOAD; } - isp->isp_osinfo.default_id = -1; + default_id = -1; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "iid", &tval) == 0) { - isp->isp_osinfo.default_id = tval; + default_id = tval; isp->isp_confopts |= ISP_CFG_OWNLOOPID; } - if (isp->isp_osinfo.default_id == -1) { + if (default_id == -1) { /* * XXX: should be a way to get properties w/o having * XXX: to call OF_xxx functions */ - isp->isp_osinfo.default_id = 7; + default_id = 7; } + ISP_SPI_PC(isp, 0)->iid = default_id; isp_debug = 0; (void) resource_int_value(device_get_name(dev), device_get_unit(dev), @@ -328,20 +309,20 @@ isp_sbus_attach(device_t dev) * Make sure we're in reset state. */ ISP_LOCK(isp); - isp_reset(isp); + isp_reset(isp, 1); if (isp->isp_state != ISP_RESETSTATE) { isp_uninit(isp); ISP_UNLOCK(isp); goto bad; } isp_init(isp); - if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { + if (role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { isp_uninit(isp); ISP_UNLOCK(isp); goto bad; } isp_attach(isp); - if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { + if (role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { isp_uninit(isp); ISP_UNLOCK(isp); goto bad; @@ -507,7 +488,7 @@ isp_sbus_mbxdma(ispsoftc_t *isp) if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR_32BIT, NULL, NULL, len, ns, - BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_cdmat)) { + BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.cdmat)) { isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces"); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); @@ -516,11 +497,11 @@ isp_sbus_mbxdma(ispsoftc_t *isp) return (1); } - if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, - &isp->isp_cdmap) != 0) { + if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT, + &isp->isp_osinfo.cdmap) != 0) { isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len); - bus_dma_tag_destroy(isp->isp_cdmat); + bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); free(isp->isp_xflist, M_DEVBUF); ISP_LOCK(isp); @@ -539,7 +520,7 @@ isp_sbus_mbxdma(ispsoftc_t *isp) } goto bad; } - isp_callout_init(&pcmd->wdog); + callout_init_mtx(&pcmd->wdog, &isp->isp_osinfo.lock, 0); if (i == isp->isp_maxcmds-1) { pcmd->next = NULL; } else { @@ -550,7 +531,7 @@ isp_sbus_mbxdma(ispsoftc_t *isp) im.isp = isp; im.error = 0; - bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); + bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0); if (im.error) { isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error); @@ -564,8 +545,8 @@ isp_sbus_mbxdma(ispsoftc_t *isp) return (0); bad: - bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); - bus_dma_tag_destroy(isp->isp_cdmat); + bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); + bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_xflist, M_DEVBUF); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); isp->isp_rquest = NULL; @@ -576,15 +557,13 @@ isp_sbus_mbxdma(ispsoftc_t *isp) typedef struct { ispsoftc_t *isp; void *cmd_token; - void *rq; - uint32_t *nxtip; - uint32_t optr; + void *rq; /* original request */ int error; + bus_size_t mapsize; } mush_t; #define MUSHERR_NOQENTRIES -2 - static void dma2(void *, bus_dma_segment_t *, int, int); static void @@ -593,154 +572,84 @@ dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) mush_t *mp; ispsoftc_t *isp; struct ccb_scsiio *csio; - bus_dma_segment_t *eseg; + isp_ddir_t ddir; ispreq_t *rq; - int seglim, datalen; - uint16_t nxti; mp = (mush_t *) arg; if (error) { mp->error = error; return; } - - if (nseg < 1) { - isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); - mp->error = EFAULT; - return; - } csio = mp->cmd_token; isp = mp->isp; rq = mp->rq; - nxti = *mp->nxtip; - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); - } else { - bus_dmamap_sync(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); - } - - datalen = XS_XFRLEN(csio); - - /* - * We're passed an initial partially filled in entry that - * has most fields filled in except for data transfer - * related values. - * - * Our job is to fill in the initial request queue entry and - * then to start allocating and filling in continuation entries - * until we've covered the entire transfer. - */ - - if (csio->cdb_len > 12) { - seglim = 0; - } else { - seglim = ISP_RQDSEG; - } - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { - rq->req_flags |= REQFLAG_DATA_IN; - } else { - rq->req_flags |= REQFLAG_DATA_OUT; - } - - eseg = dm_segs + nseg; - - while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { - rq->req_dataseg[rq->req_seg_count].ds_base = dm_segs->ds_addr; - rq->req_dataseg[rq->req_seg_count].ds_count = dm_segs->ds_len; - datalen -= dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - } - - while (datalen > 0 && dm_segs != eseg) { - uint16_t onxti; - ispcontreq_t local, *crq = &local, *cqe; - - cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - onxti = nxti; - nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == mp->optr) { - isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); - mp->error = MUSHERR_NOQENTRIES; - return; + if (nseg) { + if (sizeof (bus_addr_t) > 4) { + if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) { + rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; + } else if (rq->req_header.rqs_entry_type == RQSTYPE_REQUEST) { + rq->req_header.rqs_entry_type = RQSTYPE_A64; + } } - rq->req_header.rqs_entry_count++; - MEMZERO((void *)crq, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; - - seglim = 0; - while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { - crq->req_dataseg[seglim].ds_base = - dm_segs->ds_addr; - crq->req_dataseg[seglim].ds_count = - dm_segs->ds_len; - rq->req_seg_count++; - dm_segs++; - seglim++; - datalen -= dm_segs->ds_len; + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREREAD); + ddir = ISP_FROM_DEVICE; + } else if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_PREWRITE); + ddir = ISP_TO_DEVICE; + } else { + ddir = ISP_NOXFR; } - isp_put_cont_req(isp, crq, cqe); - MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); + } else { + dm_segs = NULL; + nseg = 0; + ddir = ISP_NOXFR; + } + + if (isp_send_cmd(isp, rq, dm_segs, nseg, XS_XFRLEN(csio), ddir) != CMD_QUEUED) { + mp->error = MUSHERR_NOQENTRIES; } - *mp->nxtip = nxti; } static int -isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, - uint32_t *nxtip, uint32_t optr) +isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff) { - ispreq_t *qep; mush_t mush, *mp; void (*eptr)(void *, bus_dma_segment_t *, int, int); - qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - eptr = dma2; - - - if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || - (csio->dxfer_len == 0)) { - rq->req_seg_count = 1; - goto mbxsync; - } - - /* - * Do a virtual grapevine step to collect info for - * the callback dma allocation that we have to use... - */ mp = &mush; mp->isp = isp; mp->cmd_token = csio; - mp->rq = rq; - mp->nxtip = nxtip; - mp->optr = optr; + mp->rq = ff; mp->error = 0; + mp->mapsize = 0; - if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { + eptr = dma2; + + if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || (csio->dxfer_len == 0)) { + (*eptr)(mp, NULL, 0, 0); + } else if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { - int error = bus_dmamap_load(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap, csio->data_ptr, - csio->dxfer_len, eptr, mp, 0); + int error; + error = bus_dmamap_load(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, csio->data_ptr, csio->dxfer_len, eptr, mp, 0); +#if 0 + xpt_print(csio->ccb_h.path, "%s: bus_dmamap_load " "ptr %p len %d returned %d\n", __func__, csio->data_ptr, csio->dxfer_len, error); +#endif + if (error == EINPROGRESS) { - bus_dmamap_unload(isp->isp_osinfo.dmat, - PISP_PCMD(csio)->dmap); + bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap); mp->error = EINVAL; - isp_prt(isp, ISP_LOGERR, - "deferred dma allocation not supported"); + isp_prt(isp, ISP_LOGERR, "deferred dma allocation not supported"); } else if (error && mp->error == 0) { #ifdef DIAGNOSTIC - isp_prt(isp, ISP_LOGERR, - "error %d in dma mapping code", error); + isp_prt(isp, ISP_LOGERR, "error %d in dma mapping code", error); #endif mp->error = error; } } else { /* Pointer to physical buffer */ struct bus_dma_segment seg; - seg.ds_addr = (bus_addr_t)csio->data_ptr; + seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; seg.ds_len = csio->dxfer_len; (*eptr)(mp, &seg, 1, 0); } @@ -748,12 +657,10 @@ isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, struct bus_dma_segment *segs; if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { - isp_prt(isp, ISP_LOGERR, - "Physical segment pointers unsupported"); + isp_prt(isp, ISP_LOGERR, "Physical segment pointers unsupported"); mp->error = EINVAL; } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { - isp_prt(isp, ISP_LOGERR, - "Virtual segment addresses unsupported"); + isp_prt(isp, ISP_LOGERR, "Physical SG/LIST Phys segment pointers unsupported"); mp->error = EINVAL; } else { /* Just use the segments provided */ @@ -774,19 +681,6 @@ isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, } return (retval); } -mbxsync: - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "Request Queue Entry", QENTRY_LEN, rq); - } - switch (rq->req_header.rqs_entry_type) { - case RQSTYPE_REQUEST: - isp_put_request(isp, rq, qep); - break; - case RQSTYPE_CMDONLY: - isp_put_extended_request(isp, (ispextreq_t *)rq, - (ispextreq_t *)qep); - break; - } return (CMD_QUEUED); } diff --git a/sys/dev/isp/isp_stds.h b/sys/dev/isp/isp_stds.h index 42bffd98c74c..d0a98121a377 100644 --- a/sys/dev/isp/isp_stds.h +++ b/sys/dev/isp/isp_stds.h @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Structures that derive directly from public standards. @@ -43,7 +44,7 @@ typedef struct { uint8_t cs_ctl; uint8_t s_id[3]; uint8_t type; - uint8_t f_ctl; + uint8_t f_ctl[3]; uint8_t seq_id; uint8_t df_ctl; uint16_t seq_cnt; @@ -136,9 +137,19 @@ typedef struct { uint32_t rftid_fc4types[8]; } rft_id_t; +/* + * FCP Response IU Bits of interest + * Source: NCITS T10, Project 1144D, Revision 08 (aka FCP2r08) + */ +#define FCP_CONF_REQ 0x10 +#define FCP_RESID_UNDERFLOW 0x08 +#define FCP_RESID_OVERFLOW 0x04 +#define FCP_SNSLEN_VALID 0x02 +#define FCP_RSPLEN_VALID 0x01 + /* * FCP Response Code Definitions - * Source: NCITS T10, Project 1144D, Revision 07a (aka FCP2r07a) + * Source: NCITS T10, Project 1144D, Revision 08 (aka FCP2r08) */ #define FCP_RSPNS_CODE_OFFSET 3 @@ -176,7 +187,10 @@ typedef struct { #define ABTX 0x06 #define PRLI 0x20 #define PRLO 0x21 +#define SCN 0x22 #define TPRLO 0x24 +#define PDISC 0x50 +#define ADISC 0x52 #define RNC 0x53 /* diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c index 531f64b778cc..68c42b4558ae 100644 --- a/sys/dev/isp/isp_target.c +++ b/sys/dev/isp/isp_target.c @@ -1,17 +1,17 @@ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -23,6 +23,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters. @@ -51,12 +52,9 @@ __FBSDID("$FreeBSD$"); #endif #ifdef ISP_TARGET_MODE -static const char atiocope[] = - "ATIO returned for lun %d because it was in the middle of Bus Device Reset " - "on bus %d"; -static const char atior[] = - "ATIO returned on for lun %d on from loopid %d because a Bus Reset " - "occurred on bus %d"; +static const char atiocope[] = "ATIO returned for lun %d because it was in the middle of Bus Device Reset on bus %d"; +static const char atior[] = "ATIO returned on for lun %d on from loopid %d because a Bus Reset occurred on bus %d"; +static const char rqo[] = "%s: Request Queue Overflow"; static void isp_got_msg(ispsoftc_t *, in_entry_t *); static void isp_got_msg_fc(ispsoftc_t *, in_fcentry_t *); @@ -66,6 +64,7 @@ static void isp_handle_atio2(ispsoftc_t *, at2_entry_t *); static void isp_handle_ctio(ispsoftc_t *, ct_entry_t *); static void isp_handle_ctio2(ispsoftc_t *, ct2_entry_t *); static void isp_handle_ctio7(ispsoftc_t *, ct7_entry_t *); +static void isp_handle_24xx_inotify(ispsoftc_t *, in_fcentry_24xx_t *); /* * The Qlogic driver gets an interrupt to look at response queue entries. @@ -164,14 +163,16 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) #define hdrp unp.hp } unp; uint8_t local[QENTRY_LEN]; + uint16_t iid; int bus, type, level, rval = 1; + isp_notify_t notify; type = isp_get_response_type(isp, (isphdr_t *)vptr); unp.vp = vptr; ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr); - switch(type) { + switch (type) { case RQSTYPE_ATIO: if (IS_24XX(isp)) { int len; @@ -179,17 +180,15 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) isp_get_atio7(isp, at7iop, (at7_entry_t *) local); at7iop = (at7_entry_t *) local; /* - * Check for and do something with commands whose IULEN - * extends past a singel queue entry. + * Check for and do something with commands whose + * IULEN extends past a single queue entry. */ len = at7iop->at_ta_len & 0xfffff; if (len > (QENTRY_LEN - 8)) { len -= (QENTRY_LEN - 8); - isp_prt(isp, ISP_LOGINFO, - "long IU length (%d) ignored", len); + isp_prt(isp, ISP_LOGINFO, "long IU length (%d) ignored", len); while (len > 0) { - *optrp = ISP_NXT_QENTRY(*optrp, - RESULT_QUEUE_LEN(isp)); + *optrp = ISP_NXT_QENTRY(*optrp, RESULT_QUEUE_LEN(isp)); len -= QENTRY_LEN; } } @@ -203,7 +202,7 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) /* * Just go straight to outer layer for this one. */ - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, local); + isp_async(isp, ISPASYNC_TARGET_ACTION, local); } else { isp_get_atio(isp, atiop, (at_entry_t *) local); isp_handle_atio(isp, (at_entry_t *) local); @@ -216,7 +215,7 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) break; case RQSTYPE_ATIO2: - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { isp_get_atio2e(isp, at2eiop, (at2e_entry_t *) local); } else { isp_get_atio2(isp, at2iop, (at2_entry_t *) local); @@ -226,7 +225,7 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) case RQSTYPE_CTIO3: case RQSTYPE_CTIO2: - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { isp_get_ctio2e(isp, ct2eiop, (ct2e_entry_t *) local); } else { isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local); @@ -242,71 +241,44 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) case RQSTYPE_ENABLE_LUN: case RQSTYPE_MODIFY_LUN: isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local); - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, local); + isp_async(isp, ISPASYNC_TARGET_ACTION, local); break; case RQSTYPE_NOTIFY: - /* - * Either the ISP received a SCSI message it can't - * handle, or it's returning an Immed. Notify entry - * we sent. We can send Immed. Notify entries to - * increment the firmware's resource count for them - * (we set this initially in the Enable Lun entry). - */ bus = 0; if (IS_24XX(isp)) { - isp_get_notify_24xx(isp, inot_24xx, - (in_fcentry_24xx_t *)local); + isp_get_notify_24xx(isp, inot_24xx, (in_fcentry_24xx_t *)local); inot_24xx = (in_fcentry_24xx_t *) local; - status = inot_24xx->in_status; - seqid = inot_24xx->in_rxid; - isp_prt(isp, ISP_LOGTDEBUG0, - "Immediate Notify status=0x%x seqid=0x%x", - status, seqid); - switch (status) { - case IN24XX_LIP_RESET: - case IN24XX_LINK_RESET: - case IN24XX_PORT_LOGOUT: - case IN24XX_PORT_CHANGED: - case IN24XX_LINK_FAILED: - case IN24XX_SRR_RCVD: - case IN24XX_ELS_RCVD: - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, - &local); - break; - default: - isp_prt(isp, ISP_LOGINFO, - "isp_target_notify: unknown status (0x%x)", - status); - isp_notify_ack(isp, local); - break; - } + isp_handle_24xx_inotify(isp, inot_24xx); break; - } else if (IS_FC(isp)) { - if (FCPARAM(isp)->isp_2klogin) { - isp_get_notify_fc_e(isp, inote_fcp, - (in_fcentry_e_t *)local); + } + if (IS_FC(isp)) { + if (ISP_CAP_2KLOGIN(isp)) { + in_fcentry_e_t *ecp = (in_fcentry_e_t *)local; + isp_get_notify_fc_e(isp, inote_fcp, ecp); + iid = ecp->in_iid; + status = ecp->in_status; + seqid = ecp->in_seqid; } else { - isp_get_notify_fc(isp, inot_fcp, - (in_fcentry_t *)local); + in_fcentry_t *fcp = (in_fcentry_t *)local; + isp_get_notify_fc(isp, inot_fcp, fcp); + iid = fcp->in_iid; + status = fcp->in_status; + seqid = fcp->in_seqid; } - inot_fcp = (in_fcentry_t *) local; - status = inot_fcp->in_status; - seqid = inot_fcp->in_seqid; } else { - isp_get_notify(isp, inotp, (in_entry_t *)local); - inotp = (in_entry_t *) local; - status = inotp->in_status & 0xff; - seqid = inotp->in_seqid; + in_entry_t *inp = (in_entry_t *)local; + isp_get_notify(isp, inotp, inp); + status = inp->in_status & 0xff; + seqid = inp->in_seqid; + iid = inp->in_iid; if (IS_DUALBUS(isp)) { - bus = GET_BUS_VAL(inotp->in_iid); - SET_BUS_VAL(inotp->in_iid, 0); + bus = GET_BUS_VAL(inp->in_iid); + SET_BUS_VAL(inp->in_iid, 0); } } - isp_prt(isp, ISP_LOGTDEBUG0, - "Immediate Notify On Bus %d, status=0x%x seqid=0x%x", - bus, status, seqid); + isp_prt(isp, ISP_LOGTDEBUG0, "Immediate Notify On Bus %d, status=0x%x seqid=0x%x", bus, status, seqid); switch (status) { case IN_MSG_RECEIVED: @@ -319,38 +291,74 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) break; case IN_RSRC_UNAVAIL: isp_prt(isp, ISP_LOGINFO, "Firmware out of ATIOs"); - isp_notify_ack(isp, local); + (void) isp_notify_ack(isp, local); break; - case IN_RESET: - { - /* - * We form the notify structure here because we need - * to mark it as needing a NOTIFY ACK on return. - */ - tmd_notify_t notify; - MEMZERO(¬ify, sizeof (tmd_notify_t)); + case IN_RESET: + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); notify.nt_hba = isp; - notify.nt_iid = INI_ANY; - /* nt_tgt set in outer layers */ + notify.nt_wwn = INI_ANY; + notify.nt_tgt = TGT_ANY; + notify.nt_nphdl = iid; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; notify.nt_lun = LUN_ANY; notify.nt_tagval = TAG_ANY; + notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); notify.nt_ncode = NT_BUS_RESET; notify.nt_need_ack = 1; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + notify.nt_lreserved = local; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; - } + case IN_PORT_LOGOUT: - case IN_ABORT_TASK: - case IN_PORT_CHANGED: - case IN_GLOBAL_LOGO: - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local); + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = iid; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_ncode = NT_LOGOUT; + notify.nt_need_ack = 1; + notify.nt_lreserved = local; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; + + case IN_ABORT_TASK: + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = iid; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_ncode = NT_ABORT_TASK; + notify.nt_need_ack = 1; + notify.nt_lreserved = local; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + break; + + case IN_GLOBAL_LOGO: + isp_prt(isp, ISP_LOGTINFO, "%s: all ports logged out", __func__); + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = NIL_HANDLE; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_ncode = NT_GLOBAL_LOGOUT; + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + (void) isp_notify_ack(isp, local); + break; + + case IN_PORT_CHANGED: + isp_prt(isp, ISP_LOGTINFO, "%s: port changed", __func__); + (void) isp_notify_ack(isp, local); + break; + default: - isp_prt(isp, ISP_LOGINFO, - "isp_target_notify: unknown status (0x%x)", - status); - isp_notify_ack(isp, local); + ISP_SNPRINTF(local, sizeof local, "%s: unknown status to RQSTYPE_NOTIFY (0x%x)", __func__, status); + isp_print_bytes(isp, local, QENTRY_LEN, vptr); + (void) isp_notify_ack(isp, local); break; } break; @@ -361,25 +369,19 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) * Immediate Notify entry for some asynchronous event. */ if (IS_24XX(isp)) { - isp_get_notify_ack_24xx(isp, nack_24xx, - (na_fcentry_24xx_t *) local); + isp_get_notify_ack_24xx(isp, nack_24xx, (na_fcentry_24xx_t *) local); nack_24xx = (na_fcentry_24xx_t *) local; if (nack_24xx->na_status != NA_OK) { level = ISP_LOGINFO; } else { level = ISP_LOGTDEBUG1; } - isp_prt(isp, level, - "Notify Ack Status=0x%x; Subcode 0x%x seqid=0x%x", - nack_24xx->na_status, nack_24xx->na_status_subcode, - nack_24xx->na_rxid); + isp_prt(isp, level, "Notify Ack Status=0x%x; Subcode 0x%x seqid=0x%x", nack_24xx->na_status, nack_24xx->na_status_subcode, nack_24xx->na_rxid); } else if (IS_FC(isp)) { - if (FCPARAM(isp)->isp_2klogin) { - isp_get_notify_ack_fc_e(isp, nacke_fcp, - (na_fcentry_e_t *)local); + if (ISP_CAP_2KLOGIN(isp)) { + isp_get_notify_ack_fc_e(isp, nacke_fcp, (na_fcentry_e_t *)local); } else { - isp_get_notify_ack_fc(isp, nack_fcp, - (na_fcentry_t *)local); + isp_get_notify_ack_fc(isp, nack_fcp, (na_fcentry_t *)local); } nack_fcp = (na_fcentry_t *)local; if (nack_fcp->na_status != NA_OK) { @@ -387,9 +389,7 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) } else { level = ISP_LOGTDEBUG1; } - isp_prt(isp, level, - "Notify Ack Status=0x%x seqid 0x%x", - nack_fcp->na_status, nack_fcp->na_seqid); + isp_prt(isp, level, "Notify Ack Status=0x%x seqid 0x%x", nack_fcp->na_status, nack_fcp->na_seqid); } else { isp_get_notify_ack(isp, nackp, (na_entry_t *)local); nackp = (na_entry_t *)local; @@ -398,15 +398,13 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) } else { level = ISP_LOGTDEBUG1; } - isp_prt(isp, level, - "Notify Ack event 0x%x status=0x%x seqid 0x%x", - nackp->na_event, nackp->na_status, nackp->na_seqid); + isp_prt(isp, level, "Notify Ack event 0x%x status=0x%x seqid 0x%x", nackp->na_event, nackp->na_status, nackp->na_seqid); } break; case RQSTYPE_ABTS_RCVD: isp_get_abts(isp, abts, (abts_t *)local); - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local); + isp_async(isp, ISPASYNC_TARGET_ACTION, &local); break; case RQSTYPE_ABTS_RSP: isp_get_abts_rsp(isp, abts_rsp, (abts_rsp_t *)local); @@ -416,15 +414,11 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) } else { level = ISP_LOGTDEBUG0; } - isp_prt(isp, level, - "ABTS RSP response[0x%x]: status=0x%x sub=(0x%x 0x%x)", - abts_rsp->abts_rsp_rxid_task, abts_rsp->abts_rsp_status, - abts_rsp->abts_rsp_payload.rsp.subcode1, - abts_rsp->abts_rsp_payload.rsp.subcode2); + isp_prt(isp, level, "ABTS RSP response[0x%x]: status=0x%x sub=(0x%x 0x%x)", abts_rsp->abts_rsp_rxid_task, abts_rsp->abts_rsp_status, + abts_rsp->abts_rsp_payload.rsp.subcode1, abts_rsp->abts_rsp_payload.rsp.subcode2); break; default: - isp_prt(isp, ISP_LOGERR, - "Unknown entry type 0x%x in isp_target_notify", type); + isp_prt(isp, ISP_LOGERR, "%s: unknown entry type 0x%x", __func__, type); rval = 0; break; } @@ -452,26 +446,23 @@ isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) return (rval); } - + /* - * Toggle (on/off) target mode for bus/target/lun + * Toggle (on/off) target mode for bus/target/lun. * * The caller has checked for overlap and legality. * * Note that not all of bus, target or lun can be paid attention to. * Note also that this action will not be complete until the f/w writes - * response entry. The caller is responsible for synchronizing this. + * a response entry. The caller is responsible for synchronizing with this. */ int -isp_lun_cmd(ispsoftc_t *isp, int cmd, int bus, int tgt, int lun, - int cmd_cnt, int inot_cnt, uint32_t opaque) +isp_lun_cmd(ispsoftc_t *isp, int cmd, int bus, int lun, int cmd_cnt, int inot_cnt) { lun_entry_t el; - uint32_t nxti, optr; void *outp; - - MEMZERO(&el, sizeof (el)); + ISP_MEMZERO(&el, sizeof (el)); if (IS_DUALBUS(isp)) { el.le_rsvd = (bus & 0x1) << 7; } @@ -495,37 +486,34 @@ isp_lun_cmd(ispsoftc_t *isp, int cmd, int bus, int tgt, int lun, } el.le_header.rqs_entry_type = cmd; el.le_header.rqs_entry_count = 1; - el.le_reserved = opaque; if (IS_SCSI(isp)) { - el.le_tgt = tgt; + el.le_tgt = SDPARAM(isp, bus)->isp_initiator_id; el.le_lun = lun; - } else if (FCPARAM(isp)->isp_sccfw == 0) { + } else if (ISP_CAP_SCCFW(isp) == 0) { el.le_lun = lun; } el.le_timeout = 30; - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { - isp_prt(isp, ISP_LOGERR, - "Request Queue Overflow in isp_lun_cmd"); + outp = isp_getrqentry(isp); + if (outp == NULL) { + isp_prt(isp, ISP_LOGERR, rqo, __func__); return (-1); } - ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el); isp_put_enable_lun(isp, &el, outp); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_lun_cmd", isp->isp_reqidx, &el); + ISP_SYNC_REQUEST(isp); return (0); } - int isp_target_put_entry(ispsoftc_t *isp, void *ap) { void *outp; - uint32_t nxti, optr; uint8_t etype = ((isphdr_t *) ap)->rqs_entry_type; - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { - isp_prt(isp, ISP_LOGWARN, - "Request Queue Overflow in isp_target_put_entry"); + outp = isp_getrqentry(isp); + if (outp == NULL) { + isp_prt(isp, ISP_LOGWARN, rqo, __func__); return (-1); } switch (etype) { @@ -533,36 +521,31 @@ isp_target_put_entry(ispsoftc_t *isp, void *ap) isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp); break; case RQSTYPE_ATIO2: - if (FCPARAM(isp)->isp_2klogin) { - isp_put_atio2e(isp, (at2e_entry_t *) ap, - (at2e_entry_t *) outp); + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_atio2e(isp, (at2e_entry_t *) ap, (at2e_entry_t *) outp); } else { - isp_put_atio2(isp, (at2_entry_t *) ap, - (at2_entry_t *) outp); + isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp); } break; case RQSTYPE_CTIO: isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp); break; case RQSTYPE_CTIO2: - if (FCPARAM(isp)->isp_2klogin) { - isp_put_ctio2e(isp, (ct2e_entry_t *) ap, - (ct2e_entry_t *) outp); + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_ctio2e(isp, (ct2e_entry_t *) ap, (ct2e_entry_t *) outp); } else { - isp_put_ctio2(isp, (ct2_entry_t *) ap, - (ct2_entry_t *) outp); + isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp); } break; case RQSTYPE_CTIO7: isp_put_ctio7(isp, (ct7_entry_t *) ap, (ct7_entry_t *) outp); break; default: - isp_prt(isp, ISP_LOGERR, - "Unknown type 0x%x in isp_put_entry", etype); + isp_prt(isp, ISP_LOGERR, "%s: Unknown type 0x%x", __func__, etype); return (-1); } - ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, __func__, isp->isp_reqidx, ap); + ISP_SYNC_REQUEST(isp); return (0); } @@ -575,17 +558,17 @@ isp_target_put_atio(ispsoftc_t *isp, void *arg) at2e_entry_t _atio2e; } atun; - MEMZERO(&atun, sizeof atun); + ISP_MEMZERO(&atun, sizeof atun); if (IS_FC(isp)) { at2_entry_t *aep = arg; atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2; atun._atio2.at_header.rqs_entry_count = 1; - if (FCPARAM(isp)->isp_sccfw) { + if (ISP_CAP_SCCFW(isp)) { atun._atio2.at_scclun = aep->at_scclun; } else { atun._atio2.at_lun = (uint8_t) aep->at_lun; } - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { atun._atio2e.at_iid = ((at2e_entry_t *)aep)->at_iid; } else { atun._atio2.at_iid = aep->at_iid; @@ -627,56 +610,91 @@ isp_target_put_atio(ispsoftc_t *isp, void *arg) */ int -isp_endcmd(ispsoftc_t *isp, void *arg, uint32_t code, uint32_t hdl) +isp_endcmd(ispsoftc_t *isp, ...) { - int sts; + uint32_t code, hdl; + uint8_t sts; union { ct_entry_t _ctio; ct2_entry_t _ctio2; ct2e_entry_t _ctio2e; ct7_entry_t _ctio7; } un; + va_list ap; - MEMZERO(&un, sizeof un); - sts = code & 0xff; + ISP_MEMZERO(&un, sizeof un); if (IS_24XX(isp)) { - at7_entry_t *aep = arg; + int vpidx, nphdl; + at7_entry_t *aep; ct7_entry_t *cto = &un._ctio7; + va_start(ap, isp); + aep = va_arg(ap, at7_entry_t *); + nphdl = va_arg(ap, int); + /* + * Note that vpidx may equal 0xff (unknown) here + */ + vpidx = va_arg(ap, int); + code = va_arg(ap, uint32_t); + hdl = va_arg(ap, uint32_t); + va_end(ap); + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] chan %d code %x", __func__, aep->at_rxid, vpidx, code); + + sts = code & 0xff; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; cto->ct_header.rqs_entry_count = 1; -/* XXXX */ cto->ct_nphdl = aep->at_hdr.seq_id; + cto->ct_nphdl = nphdl; cto->ct_rxid = aep->at_rxid; - cto->ct_iid_lo = (aep->at_hdr.s_id[1] << 8) | - aep->at_hdr.s_id[2]; + cto->ct_iid_lo = (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; cto->ct_iid_hi = aep->at_hdr.s_id[0]; cto->ct_oxid = aep->at_hdr.ox_id; cto->ct_scsi_status = sts; - cto->ct_flags = CT7_FLAG_MODE1 | CT7_NO_DATA | CT7_SENDSTATUS; - if (sts == SCSI_CHECK && (code & ECMD_SVALID)) { - cto->rsp.m1.ct_resplen = 16; + cto->ct_vpidx = vpidx; + cto->ct_flags = CT7_NOACK; + if (code & ECMD_TERMINATE) { + cto->ct_flags |= CT7_TERMINATE; + } else if (code & ECMD_SVALID) { + cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS; + cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); + cto->rsp.m1.ct_resplen = cto->ct_senselen = min(16, MAXRESPLEN_24XX); + ISP_MEMZERO(cto->rsp.m1.ct_resp, sizeof (cto->rsp.m1.ct_resp)); cto->rsp.m1.ct_resp[0] = 0xf0; cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf; cto->rsp.m1.ct_resp[7] = 8; cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff; cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff; + } else { + cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS; } if (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl) { cto->ct_resid = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl; - cto->ct_scsi_status |= CT2_DATA_UNDER; + if (cto->ct_resid < 0) { + cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8); + } else if (cto->ct_resid > 0) { + cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8); + } } cto->ct_syshandle = hdl; } else if (IS_FC(isp)) { - at2_entry_t *aep = arg; + at2_entry_t *aep; ct2_entry_t *cto = &un._ctio2; + va_start(ap, isp); + aep = va_arg(ap, at2_entry_t *); + code = va_arg(ap, uint32_t); + hdl = va_arg(ap, uint32_t); + va_end(ap); + + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] code %x", __func__, aep->at_rxid, code); + + sts = code & 0xff; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; cto->ct_header.rqs_entry_count = 1; - if (FCPARAM(isp)->isp_sccfw == 0) { + if (ISP_CAP_SCCFW(isp) == 0) { cto->ct_lun = aep->at_lun; } - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { un._ctio2e.ct_iid = ((at2e_entry_t *)aep)->at_iid; } else { cto->ct_iid = aep->at_iid; @@ -702,9 +720,17 @@ isp_endcmd(ispsoftc_t *isp, void *arg, uint32_t code, uint32_t hdl) } cto->ct_syshandle = hdl; } else { - at_entry_t *aep = arg; + at_entry_t *aep; ct_entry_t *cto = &un._ctio; + va_start(ap, isp); + aep = va_arg(ap, at_entry_t *); + code = va_arg(ap, uint32_t); + hdl = va_arg(ap, uint32_t); + va_end(ap); + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [IID %d] code %x", __func__, aep->at_iid, code); + sts = code; + cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_count = 1; cto->ct_fwhandle = aep->at_handle; @@ -729,58 +755,66 @@ isp_endcmd(ispsoftc_t *isp, void *arg, uint32_t code, uint32_t hdl) /* * These are either broadcast events or specifically CTIO fast completion */ + int isp_target_async(ispsoftc_t *isp, int bus, int event) { - tmd_notify_t notify; + isp_notify_t notify; - MEMZERO(¬ify, sizeof (tmd_notify_t)); + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); notify.nt_hba = isp; - notify.nt_iid = INI_ANY; - /* nt_tgt set in outer layers */ + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = NIL_HANDLE; + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_tgt = TGT_ANY; + notify.nt_channel = bus; notify.nt_lun = LUN_ANY; notify.nt_tagval = TAG_ANY; - - if (IS_SCSI(isp)) { - TAG_INSERT_BUS(notify.nt_tagval, bus); - } + notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); switch (event) { case ASYNC_LOOP_UP: case ASYNC_PTPMODE: + isp_prt(isp, ISP_LOGTDEBUG0, "%s: LOOP UP", __func__); notify.nt_ncode = NT_LINK_UP; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; case ASYNC_LOOP_DOWN: + isp_prt(isp, ISP_LOGTDEBUG0, "%s: LOOP DOWN", __func__); notify.nt_ncode = NT_LINK_DOWN; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; case ASYNC_LIP_ERROR: case ASYNC_LIP_F8: case ASYNC_LIP_OCCURRED: case ASYNC_LOOP_RESET: + isp_prt(isp, ISP_LOGTDEBUG0, "%s: LIP RESET", __func__); notify.nt_ncode = NT_LIP_RESET; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; case ASYNC_BUS_RESET: case ASYNC_TIMEOUT_RESET: /* XXX: where does this come from ? */ + isp_prt(isp, ISP_LOGTDEBUG0, "%s: BUS RESET", __func__); notify.nt_ncode = NT_BUS_RESET; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; case ASYNC_DEVICE_RESET: + isp_prt(isp, ISP_LOGTDEBUG0, "%s: DEVICE RESET", __func__); notify.nt_ncode = NT_TARGET_RESET; - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); break; case ASYNC_CTIO_DONE: { uint8_t storage[QENTRY_LEN]; + isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO DONE", __func__); memset(storage, 0, QENTRY_LEN); if (IS_24XX(isp)) { ct7_entry_t *ct = (ct7_entry_t *) storage; ct->ct_header.rqs_entry_type = RQSTYPE_CTIO7; ct->ct_nphdl = CT7_OK; ct->ct_syshandle = bus; - ct->ct_flags = CT7_SENDSTATUS|CT7_FASTPOST; + ct->ct_flags = CT7_SENDSTATUS; } else if (IS_FC(isp)) { /* This should also suffice for 2K login code */ ct2_entry_t *ct = (ct2_entry_t *) storage; @@ -795,14 +829,13 @@ isp_target_async(ispsoftc_t *isp, int bus, int event) ct->ct_fwhandle = bus; ct->ct_flags = CT_SENDSTATUS; } - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, storage); + isp_async(isp, ISPASYNC_TARGET_ACTION, storage); break; } default: - isp_prt(isp, ISP_LOGERR, - "isp_target_async: unknown event 0x%x", event); + isp_prt(isp, ISP_LOGERR, "%s: unknown event 0x%x", __func__, event); if (isp->isp_state == ISP_RUNSTATE) { - isp_notify_ack(isp, NULL); + (void) isp_notify_ack(isp, NULL); } break; } @@ -821,51 +854,54 @@ isp_target_async(ispsoftc_t *isp, int bus, int event) static void isp_got_msg(ispsoftc_t *isp, in_entry_t *inp) { - tmd_notify_t nt; + isp_notify_t notify; uint8_t status = inp->in_status & ~QLTM_SVALID; - MEMZERO(&nt, sizeof (nt)); - nt.nt_hba = isp; - nt.nt_iid = GET_IID_VAL(inp->in_iid); - nt.nt_tgt = inp->in_tgt; - nt.nt_lun = inp->in_lun; - IN_MAKE_TAGID(nt.nt_tagval, GET_BUS_VAL(inp->in_iid), 0, inp); - nt.nt_lreserved = inp; + ISP_MEMZERO(¬ify, sizeof (notify)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_nphdl = GET_IID_VAL(inp->in_iid); + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + notify.nt_channel = GET_BUS_VAL(inp->in_iid); + notify.nt_tgt = inp->in_tgt; + notify.nt_lun = inp->in_lun; + IN_MAKE_TAGID(notify.nt_tagval, inp); + notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); + notify.nt_lreserved = inp; if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) { switch (inp->in_msg[0]) { case MSG_ABORT: - nt.nt_ncode = NT_ABORT_TASK_SET; + notify.nt_ncode = NT_ABORT_TASK_SET; break; case MSG_BUS_DEV_RESET: - nt.nt_ncode = NT_TARGET_RESET; + notify.nt_ncode = NT_TARGET_RESET; break; case MSG_ABORT_TAG: - nt.nt_ncode = NT_ABORT_TASK; + notify.nt_ncode = NT_ABORT_TASK; break; case MSG_CLEAR_QUEUE: - nt.nt_ncode = NT_CLEAR_TASK_SET; + notify.nt_ncode = NT_CLEAR_TASK_SET; break; case MSG_REL_RECOVERY: - nt.nt_ncode = NT_CLEAR_ACA; + notify.nt_ncode = NT_CLEAR_ACA; break; case MSG_TERM_IO_PROC: - nt.nt_ncode = NT_ABORT_TASK; + notify.nt_ncode = NT_ABORT_TASK; break; case MSG_LUN_RESET: - nt.nt_ncode = NT_LUN_RESET; + notify.nt_ncode = NT_LUN_RESET; break; default: - isp_prt(isp, ISP_LOGERR, - "unhandled message 0x%x", inp->in_msg[0]); - isp_notify_ack(isp, inp); + isp_prt(isp, ISP_LOGERR, "%s: unhandled message 0x%x", __func__, inp->in_msg[0]); + (void) isp_notify_ack(isp, inp); return; } - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); } else { - isp_prt(isp, ISP_LOGERR, - "unknown immediate notify status 0x%x", inp->in_status); - isp_notify_ack(isp, inp); + isp_prt(isp, ISP_LOGERR, "%s: unknown immediate notify status 0x%x", __func__, inp->in_status); + (void) isp_notify_ack(isp, inp); } } @@ -875,169 +911,156 @@ isp_got_msg(ispsoftc_t *isp, in_entry_t *inp) static void isp_got_msg_fc(ispsoftc_t *isp, in_fcentry_t *inp) { - tmd_notify_t nt; + isp_notify_t notify; static const char f1[] = "%s from N-port handle 0x%x lun %d seq 0x%x"; - static const char f2[] = "unknown %s 0x%x lun %d N-Port handle 0x%x " - "task flags 0x%x seq 0x%x\n"; + static const char f2[] = "unknown %s 0x%x lun %d N-Port handle 0x%x task flags 0x%x seq 0x%x\n"; uint16_t seqid, loopid; - MEMZERO(&nt, sizeof (tmd_notify_t)); - nt.nt_hba = isp; - if (FCPARAM(isp)->isp_2klogin) { - nt.nt_iid = ((in_fcentry_e_t *)inp)->in_iid; + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + if (ISP_CAP_2KLOGIN(isp)) { + notify.nt_nphdl = ((in_fcentry_e_t *)inp)->in_iid; loopid = ((in_fcentry_e_t *)inp)->in_iid; seqid = ((in_fcentry_e_t *)inp)->in_seqid; } else { - nt.nt_iid = inp->in_iid; + notify.nt_nphdl = inp->in_iid; loopid = inp->in_iid; seqid = inp->in_seqid; } + notify.nt_sid = PORT_ANY; + notify.nt_did = PORT_ANY; + /* nt_tgt set in outer layers */ - if (FCPARAM(isp)->isp_sccfw) { - nt.nt_lun = inp->in_scclun; + if (ISP_CAP_SCCFW(isp)) { + notify.nt_lun = inp->in_scclun; } else { - nt.nt_lun = inp->in_lun; + notify.nt_lun = inp->in_lun; } - IN_FC_MAKE_TAGID(nt.nt_tagval, 0, 0, seqid); - nt.nt_need_ack = 1; - nt.nt_lreserved = inp; + notify.nt_tagval = seqid; + notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); + notify.nt_need_ack = 1; + notify.nt_lreserved = inp; if (inp->in_status != IN_MSG_RECEIVED) { - isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", - inp->in_status, nt.nt_lun, loopid, inp->in_task_flags, - inp->in_seqid); - isp_notify_ack(isp, inp); + isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", inp->in_status, notify.nt_lun, loopid, inp->in_task_flags, inp->in_seqid); + (void) isp_notify_ack(isp, inp); return; } if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK_SET) { - isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", - loopid, nt.nt_lun, inp->in_seqid); - nt.nt_ncode = NT_ABORT_TASK_SET; + isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", loopid, notify.nt_lun, inp->in_seqid); + notify.nt_ncode = NT_ABORT_TASK_SET; } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) { - isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", - loopid, nt.nt_lun, inp->in_seqid); - nt.nt_ncode = NT_CLEAR_TASK_SET; + isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", loopid, notify.nt_lun, inp->in_seqid); + notify.nt_ncode = NT_CLEAR_TASK_SET; } else if (inp->in_task_flags & TASK_FLAGS_LUN_RESET) { - isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", - loopid, nt.nt_lun, inp->in_seqid); - nt.nt_ncode = NT_LUN_RESET; + isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", loopid, notify.nt_lun, inp->in_seqid); + notify.nt_ncode = NT_LUN_RESET; } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) { - isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", - loopid, nt.nt_lun, inp->in_seqid); - nt.nt_ncode = NT_TARGET_RESET; + isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", loopid, notify.nt_lun, inp->in_seqid); + notify.nt_ncode = NT_TARGET_RESET; } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) { - isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", - loopid, nt.nt_lun, inp->in_seqid); - nt.nt_ncode = NT_CLEAR_ACA; + isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", loopid, notify.nt_lun, inp->in_seqid); + notify.nt_ncode = NT_CLEAR_ACA; } else { - isp_prt(isp, ISP_LOGWARN, f2, "task flag", inp->in_status, - nt.nt_lun, loopid, inp->in_task_flags, inp->in_seqid); - isp_notify_ack(isp, inp); + isp_prt(isp, ISP_LOGWARN, f2, "task flag", inp->in_status, notify.nt_lun, loopid, inp->in_task_flags, inp->in_seqid); + (void) isp_notify_ack(isp, inp); return; } - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); } -#define HILO(x) (uint32_t) (x >> 32), (uint32_t) x static void isp_got_tmf_24xx(ispsoftc_t *isp, at7_entry_t *aep) { - tmd_notify_t nt; - static const char f1[] = - "%s from PortID 0x%06x lun %d seq 0x%08x%08x"; - static const char f2[] = - "unknown Task Flag 0x%x lun %d PortID 0x%x tag 0x%08x%08x"; - uint32_t sid; + isp_notify_t notify; + static const char f1[] = "%s from PortID 0x%06x lun %d seq 0x%08x"; + static const char f2[] = "unknown Task Flag 0x%x lun %d PortID 0x%x tag 0x%08x"; + uint16_t chan; + uint32_t sid, did; - MEMZERO(&nt, sizeof (tmd_notify_t)); - nt.nt_hba = isp; - nt.nt_iid = INI_ANY; - nt.nt_lun = - (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | - (aep->at_cmnd.fcp_cmnd_lun[1]); - /* - * XXX: VPIDX HAS TO BE DERIVED FROM DESTINATION PORT - */ - nt.nt_tagval = aep->at_rxid; - nt.nt_lreserved = aep; - sid = - (aep->at_hdr.s_id[0] << 16) | - (aep->at_hdr.s_id[1] << 8) | - (aep->at_hdr.s_id[2]); + ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); + notify.nt_hba = isp; + notify.nt_wwn = INI_ANY; + notify.nt_lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | (aep->at_cmnd.fcp_cmnd_lun[1]); + notify.nt_tagval = aep->at_rxid; + notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); + notify.nt_lreserved = aep; + sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | (aep->at_hdr.s_id[2]); - if (aep->at_cmnd.fcp_cmnd_task_management & - FCP_CMND_TMF_ABORT_TASK_SET) { - isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", - sid, nt.nt_lun, HILO(nt.nt_tagval)); - nt.nt_ncode = NT_ABORT_TASK_SET; - } else if (aep->at_cmnd.fcp_cmnd_task_management & - FCP_CMND_TMF_CLEAR_TASK_SET) { - isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", - sid, nt.nt_lun, HILO(nt.nt_tagval)); - nt.nt_ncode = NT_CLEAR_TASK_SET; - } else if (aep->at_cmnd.fcp_cmnd_task_management & - FCP_CMND_TMF_LUN_RESET) { - isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", - sid, nt.nt_lun, HILO(nt.nt_tagval)); - nt.nt_ncode = NT_LUN_RESET; - } else if (aep->at_cmnd.fcp_cmnd_task_management & - FCP_CMND_TMF_TGT_RESET) { - isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", - sid, nt.nt_lun, HILO(nt.nt_tagval)); - nt.nt_ncode = NT_TARGET_RESET; - nt.nt_lun = LUN_ANY; - } else if (aep->at_cmnd.fcp_cmnd_task_management & - FCP_CMND_TMF_CLEAR_ACA) { - isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", - sid, nt.nt_lun, HILO(nt.nt_tagval)); - nt.nt_ncode = NT_CLEAR_ACA; - } else { - isp_prt(isp, ISP_LOGWARN, f2, - aep->at_cmnd.fcp_cmnd_task_management, - nt.nt_lun, sid, HILO(nt.nt_tagval)); - isp_endcmd(isp, aep, 0, 0); + /* Channel has to derived from D_ID */ + did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2]; + for (chan = 0; chan < isp->isp_nchan; chan++) { + if (FCPARAM(isp, chan)->isp_portid == did) { + break; + } + } + if (chan == isp->isp_nchan) { + isp_prt(isp, ISP_LOGWARN, "%s: D_ID 0x%x not found on any channel", __func__, did); + /* just drop on the floor */ return; } - (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); + notify.nt_nphdl = NIL_HANDLE; /* unknown here */ + notify.nt_sid = sid; + notify.nt_did = did; + notify.nt_channel = chan; + if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_ABORT_TASK_SET) { + isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", sid, notify.nt_lun, aep->at_rxid); + notify.nt_ncode = NT_ABORT_TASK_SET; + } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_CLEAR_TASK_SET) { + isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", sid, notify.nt_lun, aep->at_rxid); + notify.nt_ncode = NT_CLEAR_TASK_SET; + } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_LUN_RESET) { + isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", sid, notify.nt_lun, aep->at_rxid); + notify.nt_ncode = NT_LUN_RESET; + } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_TGT_RESET) { + isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", sid, notify.nt_lun, aep->at_rxid); + notify.nt_ncode = NT_TARGET_RESET; + } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_CLEAR_ACA) { + isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", sid, notify.nt_lun, aep->at_rxid); + notify.nt_ncode = NT_CLEAR_ACA; + } else { + isp_prt(isp, ISP_LOGWARN, f2, aep->at_cmnd.fcp_cmnd_task_management, notify.nt_lun, sid, aep->at_rxid); + notify.nt_ncode = NT_UNKNOWN; + return; + } + isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); } -void +int isp_notify_ack(ispsoftc_t *isp, void *arg) { char storage[QENTRY_LEN]; - uint32_t nxti, optr; void *outp; - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { - isp_prt(isp, ISP_LOGWARN, - "Request Queue Overflow For isp_notify_ack"); - return; - } - - MEMZERO(storage, QENTRY_LEN); - + /* + * This is in case a Task Management Function ends up here. + */ if (IS_24XX(isp) && arg != NULL && (((isphdr_t *)arg)->rqs_entry_type == RQSTYPE_ATIO)) { at7_entry_t *aep = arg; - isp_endcmd(isp, aep, 0, 0); - return; - } else if (IS_24XX(isp) && arg != NULL && (((isphdr_t *)arg)->rqs_entry_type == RQSTYPE_ABTS_RSP)) { - abts_rsp_t *abts_rsp = (abts_rsp_t *) storage; - /* - * The caller will have set response values as appropriate - * in the ABTS structure just before calling us. - */ - MEMCPY(abts_rsp, arg, QENTRY_LEN); - isp_put_abts_rsp(isp, abts_rsp, (abts_rsp_t *)outp); - } else if (IS_24XX(isp)) { + return (isp_endcmd(isp, aep, NIL_HANDLE, 0, 0, 0)); + } + + outp = isp_getrqentry(isp); + if (outp == NULL) { + isp_prt(isp, ISP_LOGWARN, rqo, __func__); + return (1); + } + + ISP_MEMZERO(storage, QENTRY_LEN); + + if (IS_24XX(isp)) { na_fcentry_24xx_t *na = (na_fcentry_24xx_t *) storage; if (arg) { in_fcentry_24xx_t *in = arg; na->na_nphdl = in->in_nphdl; + na->na_flags = in->in_flags & IN24XX_FLAG_PUREX_IOCB; na->na_status = in->in_status; na->na_status_subcode = in->in_status_subcode; na->na_rxid = in->in_rxid; na->na_oxid = in->in_oxid; + na->na_vpidx = in->in_vpidx; if (in->in_status == IN24XX_SRR_RCVD) { na->na_srr_rxid = in->in_srr_rxid; na->na_srr_reloff_hi = in->in_srr_reloff_hi; @@ -1058,17 +1081,15 @@ isp_notify_ack(ispsoftc_t *isp, void *arg) if (arg) { in_fcentry_t *inp = arg; - MEMCPY(storage, arg, sizeof (isphdr_t)); - if (FCPARAM(isp)->isp_2klogin) { - ((na_fcentry_e_t *)na)->na_iid = - ((in_fcentry_e_t *)inp)->in_iid; + ISP_MEMCPY(storage, arg, sizeof (isphdr_t)); + if (ISP_CAP_2KLOGIN(isp)) { + ((na_fcentry_e_t *)na)->na_iid = ((in_fcentry_e_t *)inp)->in_iid; iid = ((na_fcentry_e_t *)na)->na_iid; } else { na->na_iid = inp->in_iid; iid = na->na_iid; } - na->na_task_flags = - inp->in_task_flags & TASK_FLAGS_RESERVED_MASK; + na->na_task_flags = inp->in_task_flags & TASK_FLAGS_RESERVED_MASK; na->na_seqid = inp->in_seqid; na->na_flags = NAFC_RCOUNT; na->na_status = inp->in_status; @@ -1084,20 +1105,18 @@ isp_notify_ack(ispsoftc_t *isp, void *arg) } na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; na->na_header.rqs_entry_count = 1; - if (FCPARAM(isp)->isp_2klogin) { - isp_put_notify_ack_fc_e(isp, (na_fcentry_e_t *) na, - (na_fcentry_e_t *)outp); + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_notify_ack_fc_e(isp, (na_fcentry_e_t *) na, (na_fcentry_e_t *)outp); } else { isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp); } - isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u seqid %x " - "flags %x tflags %x response %x", iid, na->na_seqid, + isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u seqid %x flags %x tflags %x response %x", iid, na->na_seqid, na->na_flags, na->na_task_flags, na->na_response); } else { na_entry_t *na = (na_entry_t *) storage; if (arg) { in_entry_t *inp = arg; - MEMCPY(storage, arg, sizeof (isphdr_t)); + ISP_MEMCPY(storage, arg, sizeof (isphdr_t)); na->na_iid = inp->in_iid; na->na_lun = inp->in_lun; na->na_tgt = inp->in_tgt; @@ -1111,12 +1130,90 @@ isp_notify_ack(ispsoftc_t *isp, void *arg) na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; na->na_header.rqs_entry_count = 1; isp_put_notify_ack(isp, na, (na_entry_t *)outp); - isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u lun %u tgt " - "%u seqid %x event %x", na->na_iid, na->na_lun, na->na_tgt, - na->na_seqid, na->na_event); + isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u lun %u tgt %u seqid %x event %x", na->na_iid, na->na_lun, na->na_tgt, na->na_seqid, na->na_event); } - ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_notify_ack", isp->isp_reqidx, storage); + ISP_SYNC_REQUEST(isp); + return (0); +} + +int +isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) +{ + char storage[QENTRY_LEN]; + uint16_t tmpw; + uint8_t tmpb; + abts_t *abts = arg; + abts_rsp_t *rsp = (abts_rsp_t *) storage; + void *outp; + + if (!IS_24XX(isp)) { + isp_prt(isp, ISP_LOGERR, "%s: called for non-24XX card", __func__); + return (0); + } + + if (abts->abts_header.rqs_entry_type != RQSTYPE_ABTS_RCVD) { + isp_prt(isp, ISP_LOGERR, "%s: called for non-ABTS entry (0x%x)", __func__, abts->abts_header.rqs_entry_type); + return (0); + } + + outp = isp_getrqentry(isp); + if (outp == NULL) { + isp_prt(isp, ISP_LOGWARN, rqo, __func__); + return (1); + } + + ISP_MEMCPY(rsp, abts, QENTRY_LEN); + rsp->abts_rsp_header.rqs_entry_type = RQSTYPE_ABTS_RSP; + + /* + * Swap destination and source for response. + */ + rsp->abts_rsp_r_ctl = BA_ACC; + tmpw = rsp->abts_rsp_did_lo; + tmpb = rsp->abts_rsp_did_hi; + rsp->abts_rsp_did_lo = rsp->abts_rsp_sid_lo; + rsp->abts_rsp_did_hi = rsp->abts_rsp_sid_hi; + rsp->abts_rsp_sid_lo = tmpw; + rsp->abts_rsp_sid_hi = tmpb; + + rsp->abts_rsp_f_ctl_hi ^= 0x80; /* invert Exchange Context */ + rsp->abts_rsp_f_ctl_hi &= ~0x7f; /* clear Sequence Initiator and other bits */ + rsp->abts_rsp_f_ctl_hi |= 0x10; /* abort the whole exchange */ + rsp->abts_rsp_f_ctl_hi |= 0x8; /* last data frame of sequence */ + rsp->abts_rsp_f_ctl_hi |= 0x1; /* transfer Sequence Initiative */ + rsp->abts_rsp_f_ctl_lo = 0; + + if (errno == 0) { + uint16_t rx_id, ox_id; + + rx_id = rsp->abts_rsp_rx_id; + ox_id = rsp->abts_rsp_ox_id; + ISP_MEMZERO(&rsp->abts_rsp_payload.ba_acc, sizeof (rsp->abts_rsp_payload.ba_acc)); + isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS of 0x%x being BA_ACC'd", rsp->abts_rsp_rxid_abts, rsp->abts_rsp_rxid_task); + rsp->abts_rsp_payload.ba_acc.aborted_rx_id = rx_id; + rsp->abts_rsp_payload.ba_acc.aborted_ox_id = ox_id; + rsp->abts_rsp_payload.ba_acc.high_seq_cnt = 0xffff; + } else { + ISP_MEMZERO(&rsp->abts_rsp_payload.ba_rjt, sizeof (rsp->abts_rsp_payload.ba_acc)); + switch (errno) { + case ENOMEM: + rsp->abts_rsp_payload.ba_rjt.reason = 5; /* Logical Busy */ + break; + default: + rsp->abts_rsp_payload.ba_rjt.reason = 9; /* Unable to perform command request */ + break; + } + } + + /* + * The caller will have set response values as appropriate + * in the ABTS structure just before calling us. + */ + isp_put_abts_rsp(isp, rsp, (abts_rsp_t *)outp); + ISP_TDQE(isp, "isp_acknak_abts", isp->isp_reqidx, storage); + ISP_SYNC_REQUEST(isp); + return (0); } static void @@ -1136,13 +1233,12 @@ isp_handle_atio(ispsoftc_t *isp, at_entry_t *aep) * about this so it's ignored. */ - switch(aep->at_status & ~QLTM_SVALID) { + switch (aep->at_status & ~QLTM_SVALID) { case AT_PATH_INVALID: /* * ATIO rejected by the firmware due to disabled lun. */ - isp_prt(isp, ISP_LOGERR, - "rejected ATIO for disabled lun %d", lun); + isp_prt(isp, ISP_LOGERR, "rejected ATIO for disabled lun %d", lun); break; case AT_NOCAP: /* @@ -1150,9 +1246,7 @@ isp_handle_atio(ispsoftc_t *isp, at_entry_t *aep) * We sent an ATIO that overflowed the firmware's * command resource count. */ - isp_prt(isp, ISP_LOGERR, - "rejected ATIO for lun %d because of command count" - " overflow", lun); + isp_prt(isp, ISP_LOGERR, "rejected ATIO for lun %d because of command count overflow", lun); break; case AT_BDR_MSG: @@ -1165,8 +1259,7 @@ isp_handle_atio(ispsoftc_t *isp, at_entry_t *aep) * not increment it. Therefore we should never get * this status here. */ - isp_prt(isp, ISP_LOGERR, atiocope, lun, - GET_BUS_VAL(aep->at_iid)); + isp_prt(isp, ISP_LOGERR, atiocope, lun, GET_BUS_VAL(aep->at_iid)); break; case AT_CDB: /* Got a CDB */ @@ -1174,7 +1267,7 @@ isp_handle_atio(ispsoftc_t *isp, at_entry_t *aep) /* * Punt to platform specific layer. */ - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); + isp_async(isp, ISPASYNC_TARGET_ACTION, aep); break; case AT_RESET: @@ -1186,15 +1279,12 @@ isp_handle_atio(ispsoftc_t *isp, at_entry_t *aep) * Ignore it because the async event will clear things * up for us. */ - isp_prt(isp, ISP_LOGWARN, atior, lun, - GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); + isp_prt(isp, ISP_LOGWARN, atior, lun, GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); break; default: - isp_prt(isp, ISP_LOGERR, - "Unknown ATIO status 0x%x from loopid %d for lun %d", - aep->at_status, aep->at_iid, lun); + isp_prt(isp, ISP_LOGERR, "Unknown ATIO status 0x%x from loopid %d for lun %d", aep->at_status, aep->at_iid, lun); (void) isp_target_put_atio(isp, aep); break; } @@ -1205,13 +1295,13 @@ isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) { int lun, iid; - if (FCPARAM(isp)->isp_sccfw) { + if (ISP_CAP_SCCFW(isp)) { lun = aep->at_scclun; } else { lun = aep->at_lun; } - if (FCPARAM(isp)->isp_2klogin) { + if (ISP_CAP_2KLOGIN(isp)) { iid = ((at2e_entry_t *)aep)->at_iid; } else { iid = aep->at_iid; @@ -1229,13 +1319,12 @@ isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) * about this so it's ignored. */ - switch(aep->at_status & ~QLTM_SVALID) { + switch (aep->at_status & ~QLTM_SVALID) { case AT_PATH_INVALID: /* * ATIO rejected by the firmware due to disabled lun. */ - isp_prt(isp, ISP_LOGERR, - "rejected ATIO2 for disabled lun %d", lun); + isp_prt(isp, ISP_LOGERR, "rejected ATIO2 for disabled lun %d", lun); break; case AT_NOCAP: /* @@ -1243,8 +1332,7 @@ isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) * We sent an ATIO that overflowed the firmware's * command resource count. */ - isp_prt(isp, ISP_LOGERR, - "rejected ATIO2 for lun %d- command count overflow", lun); + isp_prt(isp, ISP_LOGERR, "rejected ATIO2 for lun %d- command count overflow", lun); break; case AT_BDR_MSG: @@ -1264,7 +1352,7 @@ isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) /* * Punt to platform specific layer. */ - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); + isp_async(isp, ISPASYNC_TARGET_ACTION, aep); break; case AT_RESET: @@ -1281,9 +1369,7 @@ isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) default: - isp_prt(isp, ISP_LOGERR, - "Unknown ATIO2 status 0x%x from loopid %d for lun %d", - aep->at_status, iid, lun); + isp_prt(isp, ISP_LOGERR, "Unknown ATIO2 status 0x%x from loopid %d for lun %d", aep->at_status, iid, lun); (void) isp_target_put_atio(isp, aep); break; } @@ -1305,7 +1391,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) xs = NULL; } - switch(ct->ct_status & ~QLTM_SVALID) { + switch (ct->ct_status & ~QLTM_SVALID) { case CT_OK: /* * There are generally 3 possibilities as to why we'd get @@ -1321,8 +1407,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) /* * Nothing to do in this case. */ - isp_prt(isp, pl, "CTIO- iid %d disconnected OK", - ct->ct_iid); + isp_prt(isp, pl, "CTIO- iid %d disconnected OK", ct->ct_iid); return; } break; @@ -1351,7 +1436,6 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) */ if (fmsg == NULL) fmsg = "ABORT TAG message sent by Initiator"; - isp_prt(isp, ISP_LOGTDEBUG0, "CTIO destroyed by %s", fmsg); break; @@ -1360,9 +1444,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) * CTIO rejected by the firmware due to disabled lun. * "Cannot Happen". */ - isp_prt(isp, ISP_LOGERR, - "Firmware rejected CTIO for disabled lun %d", - ct->ct_lun); + isp_prt(isp, ISP_LOGERR, "Firmware rejected CTIO for disabled lun %d", ct->ct_lun); break; case CT_NOPATH: @@ -1372,9 +1454,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) * we tried to access the bus while a non-disconnecting * command is in process. */ - isp_prt(isp, ISP_LOGERR, - "Firmware rejected CTIO for bad nexus %d/%d/%d", - ct->ct_iid, ct->ct_tgt, ct->ct_lun); + isp_prt(isp, ISP_LOGERR, "Firmware rejected CTIO for bad nexus %d/%d/%d", ct->ct_iid, ct->ct_tgt, ct->ct_lun); break; case CT_RSELTMO: @@ -1383,7 +1463,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) case CT_TIMEOUT: if (fmsg == NULL) fmsg = "Command"; - isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); + isp_prt(isp, ISP_LOGWARN, "Firmware timed out on %s", fmsg); break; case CT_PANIC: @@ -1408,8 +1488,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); break; default: - isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x", - ct->ct_status & ~QLTM_SVALID); + isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x", ct->ct_status & ~QLTM_SVALID); break; } @@ -1423,16 +1502,12 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) */ if (ct->ct_syshandle == 0) { if ((ct->ct_flags & CT_SENDSTATUS) == 0) { - isp_prt(isp, pl, - "intermediate CTIO completed ok"); + isp_prt(isp, pl, "intermediate CTIO completed ok"); } else { - isp_prt(isp, pl, - "unmonitored CTIO completed ok"); + isp_prt(isp, pl, "unmonitored CTIO completed ok"); } } else { - isp_prt(isp, pl, - "NO xs for CTIO (handle 0x%x) status 0x%x", - ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); + isp_prt(isp, pl, "NO xs for CTIO (handle 0x%x) status 0x%x", ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); } } else { /* @@ -1446,7 +1521,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) /* * The platform layer will destroy the handle if appropriate. */ - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); + isp_async(isp, ISPASYNC_TARGET_ACTION, ct); } } @@ -1466,7 +1541,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) xs = NULL; } - switch(ct->ct_status & ~QLTM_SVALID) { + switch (ct->ct_status & ~QLTM_SVALID) { case CT_BUS_ERROR: isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); /* FALL Through */ @@ -1507,8 +1582,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) fmsg = "ABORT"; } - isp_prt(isp, ISP_LOGTDEBUG0, - "CTIO2 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); + isp_prt(isp, ISP_LOGTDEBUG0, "CTIO2 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); break; case CT_INVAL: @@ -1524,7 +1598,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) case CT_TIMEOUT: if (fmsg == NULL) fmsg = "command"; - isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); + isp_prt(isp, ISP_LOGWARN, "Firmware timed out on %s", fmsg); break; case CT_ERR: @@ -1553,13 +1627,11 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) * CTIO rejected by the firmware because an invalid RX_ID. * Just print a message. */ - isp_prt(isp, ISP_LOGWARN, - "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); + isp_prt(isp, ISP_LOGWARN, "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); break; default: - isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", - ct->ct_status & ~QLTM_SVALID); + isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", ct->ct_status & ~QLTM_SVALID); break; } @@ -1573,16 +1645,12 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) */ if (ct->ct_syshandle == 0) { if ((ct->ct_flags & CT2_SENDSTATUS) == 0) { - isp_prt(isp, pl, - "intermediate CTIO completed ok"); + isp_prt(isp, pl, "intermediate CTIO completed ok"); } else { - isp_prt(isp, pl, - "unmonitored CTIO completed ok"); + isp_prt(isp, pl, "unmonitored CTIO completed ok"); } } else { - isp_prt(isp, pl, - "NO xs for CTIO (handle 0x%x) status 0x%x", - ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); + isp_prt(isp, pl, "NO xs for CTIO (handle 0x%x) status 0x%x", ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); } } else { if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { @@ -1605,7 +1673,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) */ isp_prt(isp, pl, "data CTIO complete"); } - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); + isp_async(isp, ISPASYNC_TARGET_ACTION, ct); /* * The platform layer will destroy the handle if appropriate. */ @@ -1628,7 +1696,7 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) xs = NULL; } - switch(ct->ct_nphdl) { + switch (ct->ct_nphdl) { case CT7_BUS_ERROR: isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); /* FALL Through */ @@ -1658,15 +1726,14 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) if (fmsg == NULL) { fmsg = "ABORT"; } - isp_prt(isp, ISP_LOGTDEBUG0, - "CTIO7 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); + isp_prt(isp, ISP_LOGTDEBUG0, "CTIO7 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); break; case CT7_TIMEOUT: if (fmsg == NULL) { fmsg = "command"; } - isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); + isp_prt(isp, ISP_LOGWARN, "Firmware timed out on %s", fmsg); break; case CT7_ERR: @@ -1694,8 +1761,7 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) * CTIO rejected by the firmware because an invalid RX_ID. * Just print a message. */ - isp_prt(isp, ISP_LOGWARN, - "CTIO7 completed with Invalid RX_ID 0x%x", ct->ct_rxid); + isp_prt(isp, ISP_LOGWARN, "CTIO7 completed with Invalid RX_ID 0x%x", ct->ct_rxid); break; case CT7_REASSY_ERR: @@ -1707,8 +1773,7 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) break; default: - isp_prt(isp, ISP_LOGERR, "Unknown CTIO7 status 0x%x", - ct->ct_nphdl); + isp_prt(isp, ISP_LOGERR, "Unknown CTIO7 status 0x%x", ct->ct_nphdl); break; } @@ -1722,26 +1787,20 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) */ if (ct->ct_syshandle == 0) { if (ct->ct_flags & CT7_TERMINATE) { - isp_prt(isp, ISP_LOGINFO, - "termination of 0x%x complete", - ct->ct_rxid); + isp_prt(isp, ISP_LOGINFO, "termination of 0x%x complete", ct->ct_rxid); } else if ((ct->ct_flags & CT7_SENDSTATUS) == 0) { - isp_prt(isp, pl, - "intermediate CTIO completed ok"); + isp_prt(isp, pl, "intermediate CTIO completed ok"); } else { - isp_prt(isp, pl, - "unmonitored CTIO completed ok"); + isp_prt(isp, pl, "unmonitored CTIO completed ok"); } } else { - isp_prt(isp, pl, - "NO xs for CTIO (handle 0x%x) status 0x%x", - ct->ct_syshandle, ct->ct_nphdl); + isp_prt(isp, pl, "NO xs for CTIO (handle 0x%x) status 0x%x", ct->ct_syshandle, ct->ct_nphdl); } } else { - if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { + if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) { ISP_DMAFREE(isp, xs, ct->ct_syshandle); } - if (ct->ct_flags & CT2_SENDSTATUS) { + if (ct->ct_flags & CT7_SENDSTATUS) { /* * Sent status and command complete. * @@ -1758,10 +1817,56 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) */ isp_prt(isp, pl, "data CTIO complete"); } - (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); + isp_async(isp, ISPASYNC_TARGET_ACTION, ct); /* * The platform layer will destroy the handle if appropriate. */ } } + +static void +isp_handle_24xx_inotify(ispsoftc_t *isp, in_fcentry_24xx_t *inot_24xx) +{ + uint8_t ochan, chan, lochan, hichan; + + /* + * Check to see whether we got a wildcard channel. + * If so, we have to iterate over all channels. + */ + ochan = chan = ISP_GET_VPIDX(isp, inot_24xx->in_vpidx); + if (chan == 0xff) { + lochan = 0; + hichan = isp->isp_nchan; + } else { + if (chan >= isp->isp_nchan) { + char buf[64]; + ISP_SNPRINTF(buf, sizeof buf, "%s: bad channel %d for status 0x%x", __func__, chan, inot_24xx->in_status); + isp_print_bytes(isp, buf, QENTRY_LEN, inot_24xx); + (void) isp_notify_ack(isp, inot_24xx); + return; + } + lochan = chan; + hichan = chan + 1; + } + isp_prt(isp, ISP_LOGTDEBUG1, "%s: Immediate Notify Channels %d..%d status=0x%x seqid=0x%x", __func__, lochan, hichan-1, inot_24xx->in_status, inot_24xx->in_rxid); + for (chan = lochan; chan < hichan; chan++) { + switch (inot_24xx->in_status) { + case IN24XX_LIP_RESET: + case IN24XX_LINK_RESET: + case IN24XX_PORT_LOGOUT: + case IN24XX_PORT_CHANGED: + case IN24XX_LINK_FAILED: + case IN24XX_SRR_RCVD: + case IN24XX_ELS_RCVD: + inot_24xx->in_vpidx = chan; + isp_async(isp, ISPASYNC_TARGET_ACTION, inot_24xx); + break; + default: + isp_prt(isp, ISP_LOGINFO, "%s: unhandled status (0x%x) for chan %d", __func__, inot_24xx->in_status, chan); + (void) isp_notify_ack(isp, inot_24xx); + break; + } + } + inot_24xx->in_vpidx = ochan; +} #endif diff --git a/sys/dev/isp/isp_target.h b/sys/dev/isp/isp_target.h index e57df6cc3549..9905c4fbcb32 100644 --- a/sys/dev/isp/isp_target.h +++ b/sys/dev/isp/isp_target.h @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Qlogic Target Mode Structure and Flag Definitions @@ -31,858 +32,56 @@ #ifndef _ISP_TARGET_H #define _ISP_TARGET_H -#define QLTM_SENSELEN 18 /* non-FC cards only */ -#define QLTM_SVALID 0x80 - /* - * Structure for Enable Lun and Modify Lun queue entries + * Notify structure- these are for asynchronous events that need to be sent + * as notifications to the outer layer. It should be pretty self-explanatory. */ -typedef struct { - isphdr_t le_header; - uint32_t le_reserved; - uint8_t le_lun; - uint8_t le_rsvd; - uint8_t le_ops; /* Modify LUN only */ - uint8_t le_tgt; /* Not for FC */ - uint32_t le_flags; /* Not for FC */ - uint8_t le_status; - uint8_t le_reserved2; - uint8_t le_cmd_count; - uint8_t le_in_count; - uint8_t le_cdb6len; /* Not for FC */ - uint8_t le_cdb7len; /* Not for FC */ - uint16_t le_timeout; - uint16_t le_reserved3[20]; -} lun_entry_t; - -/* - * le_flags values - */ -#define LUN_TQAE 0x00000002 /* bit1 Tagged Queue Action Enable */ -#define LUN_DSSM 0x01000000 /* bit24 Disable Sending SDP Message */ -#define LUN_DISAD 0x02000000 /* bit25 Disable autodisconnect */ -#define LUN_DM 0x40000000 /* bit30 Disconnects Mandatory */ - -/* - * le_ops values - */ -#define LUN_CCINCR 0x01 /* increment command count */ -#define LUN_CCDECR 0x02 /* decrement command count */ -#define LUN_ININCR 0x40 /* increment immed. notify count */ -#define LUN_INDECR 0x80 /* decrement immed. notify count */ - -/* - * le_status values - */ -#define LUN_OK 0x01 /* we be rockin' */ -#define LUN_ERR 0x04 /* request completed with error */ -#define LUN_INVAL 0x06 /* invalid request */ -#define LUN_NOCAP 0x16 /* can't provide requested capability */ -#define LUN_ENABLED 0x3E /* LUN already enabled */ - -/* - * Immediate Notify Entry structure - */ -#define IN_MSGLEN 8 /* 8 bytes */ -#define IN_RSVDLEN 8 /* 8 words */ -typedef struct { - isphdr_t in_header; - uint32_t in_reserved; - uint8_t in_lun; /* lun */ - uint8_t in_iid; /* initiator */ - uint8_t in_reserved2; - uint8_t in_tgt; /* target */ - uint32_t in_flags; - uint8_t in_status; - uint8_t in_rsvd2; - uint8_t in_tag_val; /* tag value */ - uint8_t in_tag_type; /* tag type */ - uint16_t in_seqid; /* sequence id */ - uint8_t in_msg[IN_MSGLEN]; /* SCSI message bytes */ - uint16_t in_reserved3[IN_RSVDLEN]; - uint8_t in_sense[QLTM_SENSELEN];/* suggested sense data */ -} in_entry_t; - -typedef struct { - isphdr_t in_header; - uint32_t in_reserved; - uint8_t in_lun; /* lun */ - uint8_t in_iid; /* initiator */ - uint16_t in_scclun; - uint32_t in_reserved2; - uint16_t in_status; - uint16_t in_task_flags; - uint16_t in_seqid; /* sequence id */ -} in_fcentry_t; - -typedef struct { - isphdr_t in_header; - uint32_t in_reserved; - uint16_t in_iid; /* initiator */ - uint16_t in_scclun; - uint32_t in_reserved2; - uint16_t in_status; - uint16_t in_task_flags; - uint16_t in_seqid; /* sequence id */ -} in_fcentry_e_t; - -/* - * Values for the in_status field - */ -#define IN_REJECT 0x0D /* Message Reject message received */ -#define IN_RESET 0x0E /* Bus Reset occurred */ -#define IN_NO_RCAP 0x16 /* requested capability not available */ -#define IN_IDE_RECEIVED 0x33 /* Initiator Detected Error msg received */ -#define IN_RSRC_UNAVAIL 0x34 /* resource unavailable */ -#define IN_MSG_RECEIVED 0x36 /* SCSI message received */ -#define IN_ABORT_TASK 0x20 /* task named in RX_ID is being aborted (FC) */ -#define IN_PORT_LOGOUT 0x29 /* port has logged out (FC) */ -#define IN_PORT_CHANGED 0x2A /* port changed */ -#define IN_GLOBAL_LOGO 0x2E /* all ports logged out */ -#define IN_NO_NEXUS 0x3B /* Nexus not established */ - -/* - * Values for the in_task_flags field- should only get one at a time! - */ -#define TASK_FLAGS_RESERVED_MASK (0xe700) -#define TASK_FLAGS_CLEAR_ACA (1<<14) -#define TASK_FLAGS_TARGET_RESET (1<<13) -#define TASK_FLAGS_LUN_RESET (1<<12) -#define TASK_FLAGS_CLEAR_TASK_SET (1<<10) -#define TASK_FLAGS_ABORT_TASK_SET (1<<9) - -/* - * ISP24XX Immediate Notify - */ -typedef struct { - isphdr_t in_header; - uint32_t in_reserved; - uint16_t in_nphdl; - uint16_t in_reserved1; - uint16_t in_flags; - uint16_t in_srr_rxid; - uint16_t in_status; - uint8_t in_status_subcode; - uint8_t in_reserved2; - uint32_t in_rxid; - uint16_t in_srr_reloff_lo; - uint16_t in_srr_reloff_hi; - uint16_t in_srr_iu; - uint16_t in_srr_oxid; - uint8_t in_reserved3[18]; - uint8_t in_reserved4; - uint8_t in_vpindex; - uint32_t in_reserved5; - uint16_t in_portid_lo; - uint8_t in_portid_hi; - uint8_t in_reserved6; - uint16_t in_reserved7; - uint16_t in_oxid; -} in_fcentry_24xx_t; - -#define IN24XX_FLAG_PUREX_IOCB 0x1 -#define IN24XX_FLAG_GLOBAL_LOGOUT 0x2 - -#define IN24XX_LIP_RESET 0x0E -#define IN24XX_LINK_RESET 0x0F -#define IN24XX_PORT_LOGOUT 0x29 -#define IN24XX_PORT_CHANGED 0x2A -#define IN24XX_LINK_FAILED 0x2E -#define IN24XX_SRR_RCVD 0x45 -#define IN24XX_ELS_RCVD 0x46 /* - * login-affectin ELS received- check - * subcode for specific opcode - */ -/* - * Notify Acknowledge Entry structure - */ -#define NA_RSVDLEN 22 -typedef struct { - isphdr_t na_header; - uint32_t na_reserved; - uint8_t na_lun; /* lun */ - uint8_t na_iid; /* initiator */ - uint8_t na_reserved2; - uint8_t na_tgt; /* target */ - uint32_t na_flags; - uint8_t na_status; - uint8_t na_event; - uint16_t na_seqid; /* sequence id */ - uint16_t na_reserved3[NA_RSVDLEN]; -} na_entry_t; - -/* - * Value for the na_event field - */ -#define NA_RST_CLRD 0x80 /* Clear an async event notification */ -#define NA_OK 0x01 /* Notify Acknowledge Succeeded */ -#define NA_INVALID 0x06 /* Invalid Notify Acknowledge */ - -#define NA2_RSVDLEN 21 -typedef struct { - isphdr_t na_header; - uint32_t na_reserved; - uint8_t na_reserved1; - uint8_t na_iid; /* initiator loop id */ - uint16_t na_response; - uint16_t na_flags; - uint16_t na_reserved2; - uint16_t na_status; - uint16_t na_task_flags; - uint16_t na_seqid; /* sequence id */ - uint16_t na_reserved3[NA2_RSVDLEN]; -} na_fcentry_t; - -typedef struct { - isphdr_t na_header; - uint32_t na_reserved; - uint16_t na_iid; /* initiator loop id */ - uint16_t na_response; /* response code */ - uint16_t na_flags; - uint16_t na_reserved2; - uint16_t na_status; - uint16_t na_task_flags; - uint16_t na_seqid; /* sequence id */ - uint16_t na_reserved3[NA2_RSVDLEN]; -} na_fcentry_e_t; - -#define NAFC_RCOUNT 0x80 /* increment resource count */ -#define NAFC_RST_CLRD 0x20 /* Clear LIP Reset */ -#define NAFC_TVALID 0x10 /* task mangement response code is valid */ - -/* - * ISP24XX Notify Acknowledge - */ - -typedef struct { - isphdr_t na_header; - uint32_t na_handle; - uint16_t na_nphdl; - uint16_t na_reserved1; - uint16_t na_flags; - uint16_t na_srr_rxid; - uint16_t na_status; - uint8_t na_status_subcode; - uint8_t na_reserved2; - uint32_t na_rxid; - uint16_t na_srr_reloff_lo; - uint16_t na_srr_reloff_hi; - uint16_t na_srr_iu; - uint16_t na_srr_flags; - uint8_t na_reserved3[18]; - uint8_t na_reserved4; - uint8_t na_vpindex; - uint8_t na_srr_reject_vunique; - uint8_t na_srr_reject_explanation; - uint8_t na_srr_reject_code; - uint8_t na_reserved5; - uint8_t na_reserved6[6]; - uint16_t na_oxid; -} na_fcentry_24xx_t; - -/* - * Accept Target I/O Entry structure - */ -#define ATIO_CDBLEN 26 - -typedef struct { - isphdr_t at_header; - uint16_t at_reserved; - uint16_t at_handle; - uint8_t at_lun; /* lun */ - uint8_t at_iid; /* initiator */ - uint8_t at_cdblen; /* cdb length */ - uint8_t at_tgt; /* target */ - uint32_t at_flags; - uint8_t at_status; /* firmware status */ - uint8_t at_scsi_status; /* scsi status */ - uint8_t at_tag_val; /* tag value */ - uint8_t at_tag_type; /* tag type */ - uint8_t at_cdb[ATIO_CDBLEN]; /* received CDB */ - uint8_t at_sense[QLTM_SENSELEN];/* suggested sense data */ -} at_entry_t; - -/* - * at_flags values - */ -#define AT_NODISC 0x00008000 /* disconnect disabled */ -#define AT_TQAE 0x00000002 /* Tagged Queue Action enabled */ - -/* - * at_status values - */ -#define AT_PATH_INVALID 0x07 /* ATIO sent to firmware for disabled lun */ -#define AT_RESET 0x0E /* SCSI Bus Reset Occurred */ -#define AT_PHASE_ERROR 0x14 /* Bus phase sequence error */ -#define AT_NOCAP 0x16 /* Requested capability not available */ -#define AT_BDR_MSG 0x17 /* Bus Device Reset msg received */ -#define AT_CDB 0x3D /* CDB received */ -/* - * Macros to create and fetch and test concatenated handle and tag value macros - */ - -#define AT_MAKE_TAGID(tid, bus, inst, aep) \ - tid = aep->at_handle; \ - if (aep->at_flags & AT_TQAE) { \ - tid |= (aep->at_tag_val << 16); \ - tid |= (1 << 24); \ - } \ - tid |= (bus << 25); \ - tid |= (inst << 26) - -#define CT_MAKE_TAGID(tid, bus, inst, ct) \ - tid = ct->ct_fwhandle; \ - if (ct->ct_flags & CT_TQAE) { \ - tid |= (ct->ct_tag_val << 16); \ - tid |= (1 << 24); \ - } \ - tid |= ((bus & 0x1) << 25); \ - tid |= (inst << 26) - -#define AT_HAS_TAG(val) ((val) & (1 << 24)) -#define AT_GET_TAG(val) (((val) >> 16) & 0xff) -#define AT_GET_INST(val) (((val) >> 26) & 0x3f) -#define AT_GET_BUS(val) (((val) >> 25) & 0x1) -#define AT_GET_HANDLE(val) ((val) & 0xffff) - -#define IN_MAKE_TAGID(tid, bus, inst, inp) \ - tid = inp->in_seqid; \ - tid |= (inp->in_tag_val << 16); \ - tid |= (1 << 24); \ - tid |= (bus << 25); \ - tid |= (inst << 26) - -#define TAG_INSERT_INST(tid, inst) \ - tid &= ~(0x3ffffff); \ - tid |= (inst << 26) - -#define TAG_INSERT_BUS(tid, bus) \ - tid &= ~(1 << 25); \ - tid |= (bus << 25) - -/* - * Accept Target I/O Entry structure, Type 2 - */ -#define ATIO2_CDBLEN 16 - -typedef struct { - isphdr_t at_header; - uint32_t at_reserved; - uint8_t at_lun; /* lun or reserved */ - uint8_t at_iid; /* initiator */ - uint16_t at_rxid; /* response ID */ - uint16_t at_flags; - uint16_t at_status; /* firmware status */ - uint8_t at_crn; /* command reference number */ - uint8_t at_taskcodes; - uint8_t at_taskflags; - uint8_t at_execodes; - uint8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */ - uint32_t at_datalen; /* allocated data len */ - uint16_t at_scclun; /* SCC Lun or reserved */ - uint16_t at_wwpn[4]; /* WWPN of initiator */ - uint16_t at_reserved2[6]; - uint16_t at_oxid; -} at2_entry_t; - -typedef struct { - isphdr_t at_header; - uint32_t at_reserved; - uint16_t at_iid; /* initiator */ - uint16_t at_rxid; /* response ID */ - uint16_t at_flags; - uint16_t at_status; /* firmware status */ - uint8_t at_crn; /* command reference number */ - uint8_t at_taskcodes; - uint8_t at_taskflags; - uint8_t at_execodes; - uint8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */ - uint32_t at_datalen; /* allocated data len */ - uint16_t at_scclun; /* SCC Lun or reserved */ - uint16_t at_wwpn[4]; /* WWPN of initiator */ - uint16_t at_reserved2[6]; - uint16_t at_oxid; -} at2e_entry_t; - -#define ATIO2_WWPN_OFFSET 0x2A -#define ATIO2_OXID_OFFSET 0x3E - -#define ATIO2_TC_ATTR_MASK 0x7 -#define ATIO2_TC_ATTR_SIMPLEQ 0 -#define ATIO2_TC_ATTR_HEADOFQ 1 -#define ATIO2_TC_ATTR_ORDERED 2 -#define ATIO2_TC_ATTR_ACAQ 4 -#define ATIO2_TC_ATTR_UNTAGGED 5 - -#define ATIO2_EX_WRITE 0x1 -#define ATIO2_EX_READ 0x2 -/* - * Macros to create and fetch and test concatenated handle and tag value macros - */ -#define AT2_MAKE_TAGID(tid, bus, inst, aep) \ - tid = aep->at_rxid; \ - tid |= (((uint64_t)inst) << 32); \ - tid |= (((uint64_t)bus) << 48) - -#define CT2_MAKE_TAGID(tid, bus, inst, ct) \ - tid = ct->ct_rxid; \ - tid |= (((uint64_t)inst) << 32); \ - tid |= (((uint64_t)(bus & 0xff)) << 48) - -#define AT2_HAS_TAG(val) 1 -#define AT2_GET_TAG(val) ((val) & 0xffffffff) -#define AT2_GET_INST(val) ((val) >> 32) -#define AT2_GET_HANDLE AT2_GET_TAG -#define AT2_GET_BUS(val) (((val) >> 48) & 0xff) - -#define FC_HAS_TAG AT2_HAS_TAG -#define FC_GET_TAG AT2_GET_TAG -#define FC_GET_INST AT2_GET_INST -#define FC_GET_HANDLE AT2_GET_HANDLE - -#define IN_FC_MAKE_TAGID(tid, bus, inst, seqid) \ - tid = seqid; \ - tid |= (((uint64_t)inst) << 32); \ - tid |= (((uint64_t)(bus & 0xff)) << 48) - -#define FC_TAG_INSERT_INST(tid, inst) \ - tid &= ~0xffff00000000ull; \ - tid |= (((uint64_t)inst) << 32) - -/* - * 24XX ATIO Definition - * - * This is *quite* different from other entry types. - * First of all, it has its own queue it comes in on. - * - * Secondly, it doesn't have a normal header. - * - * Thirdly, it's just a passthru of the FCP CMND IU - * which is recorded in big endian mode. - */ -typedef struct { - uint8_t at_type; - uint8_t at_count; - /* - * Task attribute in high four bits, - * the rest is the FCP CMND IU Length. - * NB: the command can extend past the - * length for a single queue entry. - */ - uint16_t at_ta_len; - uint32_t at_rxid; - fc_hdr_t at_hdr; - fcp_cmnd_iu_t at_cmnd; -} at7_entry_t; - - -/* - * Continue Target I/O Entry structure - * Request from driver. The response from the - * ISP firmware is the same except that the last 18 - * bytes are overwritten by suggested sense data if - * the 'autosense valid' bit is set in the status byte. - */ -typedef struct { - isphdr_t ct_header; - uint16_t ct_syshandle; - uint16_t ct_fwhandle; /* required by f/w */ - uint8_t ct_lun; /* lun */ - uint8_t ct_iid; /* initiator id */ - uint8_t ct_reserved2; - uint8_t ct_tgt; /* our target id */ - uint32_t ct_flags; - uint8_t ct_status; /* isp status */ - uint8_t ct_scsi_status; /* scsi status */ - uint8_t ct_tag_val; /* tag value */ - uint8_t ct_tag_type; /* tag type */ - uint32_t ct_xfrlen; /* transfer length */ - uint32_t ct_resid; /* residual length */ - uint16_t ct_timeout; - uint16_t ct_seg_count; - ispds_t ct_dataseg[ISP_RQDSEG]; -} ct_entry_t; - -/* - * For some of the dual port SCSI adapters, port (bus #) is reported - * in the MSbit of ct_iid. Bit fields are a bit too awkward here. - * - * Note that this does not apply to FC adapters at all which can and - * do report IIDs between 0x81 && 0xfe (or 0x7ff) which represent devices - * that have logged in across a SCSI fabric. - */ -#define GET_IID_VAL(x) (x & 0x3f) -#define GET_BUS_VAL(x) ((x >> 7) & 0x1) -#define SET_IID_VAL(y, x) y = ((y & ~0x3f) | (x & 0x3f)) -#define SET_BUS_VAL(y, x) y = ((y & 0x3f) | ((x & 0x1) << 7)) - -/* - * ct_flags values - */ -#define CT_TQAE 0x00000002 /* bit 1, Tagged Queue Action enable */ -#define CT_DATA_IN 0x00000040 /* bits 6&7, Data direction */ -#define CT_DATA_OUT 0x00000080 /* bits 6&7, Data direction */ -#define CT_NO_DATA 0x000000C0 /* bits 6&7, Data direction */ -#define CT_CCINCR 0x00000100 /* bit 8, autoincrement atio count */ -#define CT_DATAMASK 0x000000C0 /* bits 6&7, Data direction */ -#define CT_INISYNCWIDE 0x00004000 /* bit 14, Do Sync/Wide Negotiation */ -#define CT_NODISC 0x00008000 /* bit 15, Disconnects disabled */ -#define CT_DSDP 0x01000000 /* bit 24, Disable Save Data Pointers */ -#define CT_SENDRDP 0x04000000 /* bit 26, Send Restore Pointers msg */ -#define CT_SENDSTATUS 0x80000000 /* bit 31, Send SCSI status byte */ - -/* - * ct_status values - * - set by the firmware when it returns the CTIO - */ -#define CT_OK 0x01 /* completed without error */ -#define CT_ABORTED 0x02 /* aborted by host */ -#define CT_ERR 0x04 /* see sense data for error */ -#define CT_INVAL 0x06 /* request for disabled lun */ -#define CT_NOPATH 0x07 /* invalid ITL nexus */ -#define CT_INVRXID 0x08 /* (FC only) Invalid RX_ID */ -#define CT_DATA_OVER 0x09 /* (FC only) Data Overrun */ -#define CT_RSELTMO 0x0A /* reselection timeout after 2 tries */ -#define CT_TIMEOUT 0x0B /* timed out */ -#define CT_RESET 0x0E /* SCSI Bus Reset occurred */ -#define CT_PARITY 0x0F /* Uncorrectable Parity Error */ -#define CT_BUS_ERROR 0x10 /* (FC Only) DMA PCI Error */ -#define CT_PANIC 0x13 /* Unrecoverable Error */ -#define CT_PHASE_ERROR 0x14 /* Bus phase sequence error */ -#define CT_DATA_UNDER 0x15 /* (FC only) Data Underrun */ -#define CT_BDR_MSG 0x17 /* Bus Device Reset msg received */ -#define CT_TERMINATED 0x19 /* due to Terminate Transfer mbox cmd */ -#define CT_PORTUNAVAIL 0x28 /* port not available */ -#define CT_LOGOUT 0x29 /* port logout */ -#define CT_PORTCHANGED 0x2A /* port changed */ -#define CT_IDE 0x33 /* Initiator Detected Error */ -#define CT_NOACK 0x35 /* Outstanding Immed. Notify. entry */ -#define CT_SRR 0x45 /* SRR Received */ -#define CT_LUN_RESET 0x48 /* Lun Reset Received */ - -/* - * When the firmware returns a CTIO entry, it may overwrite the last - * part of the structure with sense data. This starts at offset 0x2E - * into the entry, which is in the middle of ct_dataseg[1]. Rather - * than define a new struct for this, I'm just using the sense data - * offset. - */ -#define CTIO_SENSE_OFFSET 0x2E - -/* - * Entry length in u_longs. All entries are the same size so - * any one will do as the numerator. - */ -#define UINT32_ENTRY_SIZE (sizeof(at_entry_t)/sizeof(uint32_t)) - -/* - * QLA2100 CTIO (type 2) entry - */ -#define MAXRESPLEN 26 -typedef struct { - isphdr_t ct_header; - uint32_t ct_syshandle; - uint8_t ct_lun; /* lun */ - uint8_t ct_iid; /* initiator id */ - uint16_t ct_rxid; /* response ID */ - uint16_t ct_flags; - uint16_t ct_status; /* isp status */ - uint16_t ct_timeout; - uint16_t ct_seg_count; - uint32_t ct_reloff; /* relative offset */ - int32_t ct_resid; /* residual length */ - union { - /* - * The three different modes that the target driver - * can set the CTIO{2,3,4} up as. - * - * The first is for sending FCP_DATA_IUs as well as - * (optionally) sending a terminal SCSI status FCP_RSP_IU. - * - * The second is for sending SCSI sense data in an FCP_RSP_IU. - * Note that no FCP_DATA_IUs will be sent. - * - * The third is for sending FCP_RSP_IUs as built specifically - * in system memory as located by the isp_dataseg. - */ - struct { - uint32_t _reserved; - uint16_t _reserved2; - uint16_t ct_scsi_status; - uint32_t ct_xfrlen; - union { - ispds_t ct_dataseg[ISP_RQDSEG_T2]; - ispds64_t ct_dataseg64[ISP_RQDSEG_T3]; - ispdslist_t ct_dslist; - } u; - } m0; - struct { - uint16_t _reserved; - uint16_t _reserved2; - uint16_t ct_senselen; - uint16_t ct_scsi_status; - uint16_t ct_resplen; - uint8_t ct_resp[MAXRESPLEN]; - } m1; - struct { - uint32_t _reserved; - uint16_t _reserved2; - uint16_t _reserved3; - uint32_t ct_datalen; - ispds_t ct_fcp_rsp_iudata; - } m2; - } rsp; -} ct2_entry_t; - -typedef struct { - isphdr_t ct_header; - uint32_t ct_syshandle; - uint16_t ct_iid; /* initiator id */ - uint16_t ct_rxid; /* response ID */ - uint16_t ct_flags; - uint16_t ct_status; /* isp status */ - uint16_t ct_timeout; - uint16_t ct_seg_count; - uint32_t ct_reloff; /* relative offset */ - int32_t ct_resid; /* residual length */ - union { - struct { - uint32_t _reserved; - uint16_t _reserved2; - uint16_t ct_scsi_status; - uint32_t ct_xfrlen; - union { - ispds_t ct_dataseg[ISP_RQDSEG_T2]; - ispds64_t ct_dataseg64[ISP_RQDSEG_T3]; - ispdslist_t ct_dslist; - } u; - } m0; - struct { - uint16_t _reserved; - uint16_t _reserved2; - uint16_t ct_senselen; - uint16_t ct_scsi_status; - uint16_t ct_resplen; - uint8_t ct_resp[MAXRESPLEN]; - } m1; - struct { - uint32_t _reserved; - uint16_t _reserved2; - uint16_t _reserved3; - uint32_t ct_datalen; - ispds_t ct_fcp_rsp_iudata; - } m2; - } rsp; -} ct2e_entry_t; - -/* - * ct_flags values for CTIO2 - */ -#define CT2_FLAG_MODE0 0x0000 -#define CT2_FLAG_MODE1 0x0001 -#define CT2_FLAG_MODE2 0x0002 -#define CT2_FLAG_MMASK 0x0003 -#define CT2_DATA_IN 0x0040 -#define CT2_DATA_OUT 0x0080 -#define CT2_NO_DATA 0x00C0 -#define CT2_DATAMASK 0x00C0 -#define CT2_CCINCR 0x0100 -#define CT2_FASTPOST 0x0200 -#define CT2_CONFIRM 0x2000 -#define CT2_TERMINATE 0x4000 -#define CT2_SENDSTATUS 0x8000 - -/* - * ct_status values are (mostly) the same as that for ct_entry. - */ - -/* - * ct_scsi_status values- the low 8 bits are the normal SCSI status - * we know and love. The upper 8 bits are validity markers for FCP_RSP_IU - * fields. - */ -#define CT2_RSPLEN_VALID 0x0100 -#define CT2_SNSLEN_VALID 0x0200 -#define CT2_DATA_OVER 0x0400 -#define CT2_DATA_UNDER 0x0800 - -/* - * ISP24XX CTIO - */ -#define MAXRESPLEN_24XX 24 -typedef struct { - isphdr_t ct_header; - uint32_t ct_syshandle; - uint16_t ct_nphdl; /* status on returned CTIOs */ - uint16_t ct_timeout; - uint16_t ct_seg_count; - uint8_t ct_vpindex; - uint8_t ct_xflags; - uint16_t ct_iid_lo; /* low 16 bits of portid */ - uint8_t ct_iid_hi; /* hi 8 bits of portid */ - uint8_t ct_reserved; - uint32_t ct_rxid; - uint16_t ct_senselen; /* mode 0 only */ - uint16_t ct_flags; - int32_t ct_resid; /* residual length */ - uint16_t ct_oxid; - uint16_t ct_scsi_status; /* modes 0 && 1 only */ - union { - struct { - uint32_t reloff; - uint32_t reserved0; - uint32_t ct_xfrlen; - uint32_t reserved1; - ispds64_t ds; - } m0; - struct { - uint16_t ct_resplen; - uint16_t reserved; - uint8_t ct_resp[MAXRESPLEN_24XX]; - } m1; - struct { - uint32_t reserved0; - uint32_t ct_datalen; - uint32_t reserved1; - ispds64_t ct_fcp_rsp_iudata; - } m2; - } rsp; -} ct7_entry_t; - -/* - * ct_flags values for CTIO7 - */ -#define CT7_DATA_IN 0x0002 -#define CT7_DATA_OUT 0x0001 -#define CT7_NO_DATA 0x0000 -#define CT7_DATAMASK 0x003 -#define CT7_DSD_ENABLE 0x0004 -#define CT7_CONF_STSFD 0x0010 -#define CT7_EXPLCT_CONF 0x0020 -#define CT7_FLAG_MODE0 0x0000 -#define CT7_FLAG_MODE1 0x0040 -#define CT7_FLAG_MODE7 0x0080 -#define CT7_FLAG_MMASK 0x00C0 -#define CT7_FASTPOST 0x0100 -#define CT7_ATTR_MASK 0x1e00 /* task attributes from atio7 */ -#define CT7_CONFIRM 0x2000 -#define CT7_TERMINATE 0x4000 -#define CT7_SENDSTATUS 0x8000 - -/* - * Type 7 CTIO status codes - */ -#define CT7_OK 0x01 /* completed without error */ -#define CT7_ABORTED 0x02 /* aborted by host */ -#define CT7_ERR 0x04 /* see sense data for error */ -#define CT7_INVAL 0x06 /* request for disabled lun */ -#define CT7_INVRXID 0x08 /* (FC only) Invalid RX_ID */ -#define CT7_DATA_OVER 0x09 /* (FC only) Data Overrun */ -#define CT7_TIMEOUT 0x0B /* timed out */ -#define CT7_RESET 0x0E /* LIP Rset Received */ -#define CT7_BUS_ERROR 0x10 /* DMA PCI Error */ -#define CT7_REASSY_ERR 0x11 /* DMA reassembly error */ -#define CT7_DATA_UNDER 0x15 /* (FC only) Data Underrun */ -#define CT7_PORTUNAVAIL 0x28 /* port not available */ -#define CT7_LOGOUT 0x29 /* port logout */ -#define CT7_PORTCHANGED 0x2A /* port changed */ -#define CT7_SRR 0x45 /* SRR Received */ - -/* - * Other 24XX related target IOCBs - */ - -/* - * ABTS Received - */ -typedef struct { - isphdr_t abts_header; - uint8_t abts_reserved0[6]; - uint16_t abts_nphdl; - uint16_t abts_reserved1; - uint16_t abts_sof; - uint32_t abts_rxid_abts; - uint16_t abts_did_lo; - uint8_t abts_did_hi; - uint8_t abts_r_ctl; - uint16_t abts_sid_lo; - uint8_t abts_sid_hi; - uint8_t abts_cs_ctl; - uint16_t abts_fs_ctl; - uint8_t abts_f_ctl; - uint8_t abts_type; - uint16_t abts_seq_cnt; - uint8_t abts_df_ctl; - uint8_t abts_seq_id; - uint16_t abts_rx_id; - uint16_t abts_ox_id; - uint32_t abts_param; - uint8_t abts_reserved2[16]; - uint32_t abts_rxid_task; -} abts_t; - -typedef struct { - isphdr_t abts_rsp_header; - uint32_t abts_rsp_handle; - uint16_t abts_rsp_status; - uint16_t abts_rsp_nphdl; - uint16_t abts_rsp_ctl_flags; - uint16_t abts_rsp_sof; - uint32_t abts_rsp_rxid_abts; - uint16_t abts_rsp_did_lo; - uint8_t abts_rsp_did_hi; - uint8_t abts_rsp_r_ctl; - uint16_t abts_rsp_sid_lo; - uint8_t abts_rsp_sid_hi; - uint8_t abts_rsp_cs_ctl; - uint16_t abts_rsp_f_ctl_lo; - uint8_t abts_rsp_f_ctl_hi; - uint8_t abts_rsp_type; - uint16_t abts_rsp_seq_cnt; - uint8_t abts_rsp_df_ctl; - uint8_t abts_rsp_seq_id; - uint16_t abts_rsp_rx_id; - uint16_t abts_rsp_ox_id; - uint32_t abts_rsp_param; - union { - struct { - uint16_t reserved; - uint8_t last_seq_id; - uint8_t seq_id_valid; - uint16_t aborted_rx_id; - uint16_t aborted_ox_id; - uint16_t high_seq_cnt; - uint16_t low_seq_cnt; - uint8_t reserved2[4]; - } ba_acc; - struct { - uint8_t vendor_unique; - uint8_t explanation; - uint8_t reason; - uint8_t reserved; - uint8_t reserved2[12]; - } ba_rjt; - struct { - uint8_t reserved[8]; - uint32_t subcode1; - uint32_t subcode2; - } rsp; - uint8_t reserved[16]; - } abts_rsp_payload; - uint32_t abts_rsp_rxid_task; -} abts_rsp_t; - -/* terminate this ABTS exchange */ -#define ISP24XX_ABTS_RSP_TERMINATE 0x01 - -#define ISP24XX_ABTS_RSP_COMPLETE 0x00 -#define ISP24XX_ABTS_RSP_RESET 0x04 -#define ISP24XX_ABTS_RSP_ABORTED 0x05 -#define ISP24XX_ABTS_RSP_TIMEOUT 0x06 -#define ISP24XX_ABTS_RSP_INVXID 0x08 -#define ISP24XX_ABTS_RSP_LOGOUT 0x29 -#define ISP24XX_ABTS_RSP_SUBCODE 0x31 +typedef enum { + NT_UNKNOWN=0x999, + NT_ABORT_TASK=0x1000, + NT_ABORT_TASK_SET, + NT_CLEAR_ACA, + NT_CLEAR_TASK_SET, + NT_LUN_RESET, + NT_TARGET_RESET, + NT_BUS_RESET, + NT_LIP_RESET, + NT_LINK_UP, + NT_LINK_DOWN, + NT_LOGOUT, + NT_GLOBAL_LOGOUT, + NT_ARRIVED, + NT_DEPARTED, + NT_HBA_RESET +} isp_ncode_t; +typedef struct isp_notify { + void * nt_hba; /* HBA tag */ + void * nt_tmd; + void * nt_lreserved; + void * nt_hreserved; + uint64_t nt_wwn; /* source (wwn) */ + uint64_t nt_tgt; /* destination (wwn) */ + uint64_t nt_tagval; /* tag value */ + uint32_t + nt_sid : 24; /* source port id */ + uint32_t + nt_failed : 1, /* notify operation failed */ + nt_need_ack : 1, /* this notify needs an ACK */ + nt_did : 24; /* destination port id */ + uint32_t + nt_lun : 16, /* logical unit */ + nt_nphdl : 16; /* n-port handle */ + uint8_t nt_channel; /* channel id */ + isp_ncode_t nt_ncode; /* action */ +} isp_notify_t; +#define MATCH_TMD(tmd, iid, lun, tag) \ + ( \ + (tmd) && \ + (iid == INI_ANY || iid == tmd->cd_iid) && \ + (lun == LUN_ANY || lun == tmd->cd_lun) && \ + (tag == TAG_ANY || tag == tmd->cd_tagval) \ + ) /* * Debug macros */ @@ -890,56 +89,12 @@ typedef struct { #define ISP_TDQE(isp, msg, idx, arg) \ if (isp->isp_dblev & ISP_LOGTDEBUG2) isp_print_qentry(isp, msg, idx, arg) -#ifndef ISP_TOOLS /* - * The functions below are for the publicly available - * target mode functions that are internal to the Qlogic driver. + * Special Constatns */ - -/* - * This function handles new response queue entry appropriate for target mode. - */ -int isp_target_notify(ispsoftc_t *, void *, uint32_t *); - -/* - * This function externalizes the ability to acknowledge an Immediate Notify - * request. - */ -void isp_notify_ack(ispsoftc_t *, void *); - -/* - * Enable/Disable/Modify a logical unit. - * (softc, cmd, bus, tgt, lun, cmd_cnt, inotify_cnt, opaque) - */ -#define DFLT_CMND_CNT 0xfe /* unmonitored */ -#define DFLT_INOT_CNT 0xfe /* unmonitored */ -int isp_lun_cmd(ispsoftc_t *, int, int, int, int, int, int, uint32_t); - -/* - * General request queue 'put' routine for target mode entries. - */ -int isp_target_put_entry(ispsoftc_t *isp, void *); - -/* - * General routine to put back an ATIO entry- - * used for replenishing f/w resource counts. - * The argument is a pointer to a source ATIO - * or ATIO2. - */ -int isp_target_put_atio(ispsoftc_t *, void *); - -/* - * General routine to send a final CTIO for a command- used mostly for - * local responses. - */ -int isp_endcmd(ispsoftc_t *, void *, uint32_t, uint32_t); -#define ECMD_SVALID 0x100 - -/* - * Handle an asynchronous event - * - * Return nonzero if the interrupt that generated this event has been dismissed. - */ -int isp_target_async(ispsoftc_t *, int, int); -#endif +#define INI_ANY ((uint64_t) -1) +#define VALID_INI(ini) (ini != INI_NONE && ini != INI_ANY) +#define LUN_ANY 0xffff +#define TGT_ANY ((uint64_t) -1) +#define TAG_ANY ((uint64_t) 0) #endif /* _ISP_TARGET_H */ diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index 272d74e8650c..8f689379afae 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Mailbox and Queue Entry Definitions for for Qlogic ISP SCSI adapters. @@ -121,11 +122,20 @@ /* These are for the ISP2X00 FC cards */ #define MBOX_GET_LOOP_ID 0x0020 +/* for 24XX cards, outgoing mailbox 7 has these values for F or FL topologies */ +#define ISP24XX_INORDER 0x0100 +#define ISP24XX_NPIV_SAN 0x0400 +#define ISP24XX_VSAN_SAN 0x1000 +#define ISP24XX_FC_SP_SAN 0x2000 + #define MBOX_GET_FIRMWARE_OPTIONS 0x0028 #define MBOX_SET_FIRMWARE_OPTIONS 0x0038 #define MBOX_GET_RESOURCE_COUNT 0x0042 #define MBOX_REQUEST_OFFLINE_MODE 0x0043 #define MBOX_ENHANCED_GET_PDB 0x0047 +#define MBOX_INIT_FIRMWARE_MULTI_ID 0x0048 /* 2400 only */ +#define MBOX_GET_VP_DATABASE 0x0049 /* 2400 only */ +#define MBOX_GET_VP_DATABASE_ENTRY 0x004a /* 2400 only */ #define MBOX_EXEC_COMMAND_IOCB_A64 0x0054 #define MBOX_INIT_FIRMWARE 0x0060 #define MBOX_GET_INIT_CONTROL_BLOCK 0x0061 @@ -158,6 +168,7 @@ #define MBGSD_TWOGB 1 #define MBGSD_AUTO 2 #define MBGSD_FOURGB 3 /* 24XX only */ +#define MBGSD_EIGHTGB 4 /* 25XX only */ #define ISP2100_SET_PCI_PARAM 0x00ff @@ -249,6 +260,11 @@ */ #define QENTRY_LEN 64 +/* + * Special Internal Handle for IOCBs + */ +#define ISP_SPCL_HANDLE 0xa5dead5a + /* * Command Structure Definitions */ @@ -273,15 +289,6 @@ typedef struct { } ispdslist_t; -/* - * These elements get swizzled around for SBus instances. - */ -#define ISP_SWAP8(a, b) { \ - uint8_t tmp; \ - tmp = a; \ - a = b; \ - b = tmp; \ -} typedef struct { uint8_t rqs_entry_type; uint8_t rqs_entry_count; @@ -294,7 +301,9 @@ typedef struct { #define RQSFLAG_FULL 0x02 #define RQSFLAG_BADHEADER 0x04 #define RQSFLAG_BADPACKET 0x08 -#define RQSFLAG_MASK 0x0f +#define RQSFLAG_BADCOUNT 0x10 +#define RQSFLAG_BADORDER 0x20 +#define RQSFLAG_MASK 0x3f /* RQS entry_type definitions */ #define RQSTYPE_REQUEST 0x01 @@ -331,6 +340,9 @@ typedef struct { #define RQSTYPE_IP_RECV_CONT 0x24 #define RQSTYPE_CT_PASSTHRU 0x29 #define RQSTYPE_MS_PASSTHRU 0x29 +#define RQSTYPE_VP_CTRL 0x30 /* 24XX only */ +#define RQSTYPE_VP_MODIFY 0x31 /* 24XX only */ +#define RQSTYPE_RPT_ID_ACQ 0x32 /* 24XX only */ #define RQSTYPE_ABORT_IO 0x33 #define RQSTYPE_T6RQS 0x48 #define RQSTYPE_LOGIN 0x52 @@ -533,6 +545,31 @@ typedef struct { ispds64_t req_dataseg; } ispreqt7_t; +/* Task Management Request Function */ +typedef struct { + isphdr_t tmf_header; + uint32_t tmf_handle; + uint16_t tmf_nphdl; + uint8_t tmf_reserved0[2]; + uint16_t tmf_delay; + uint16_t tmf_timeout; + uint8_t tmf_lun[8]; + uint32_t tmf_flags; + uint8_t tmf_reserved1[20]; + uint16_t tmf_tidlo; + uint8_t tmf_tidhi; + uint8_t tmf_vpidx; + uint8_t tmf_reserved2[12]; +} isp24xx_tmf_t; + +#define ISP24XX_TMF_NOSEND 0x80000000 + +#define ISP24XX_TMF_LUN_RESET 0x00000010 +#define ISP24XX_TMF_ABORT_TASK_SET 0x00000008 +#define ISP24XX_TMF_CLEAR_TASK_SET 0x00000004 +#define ISP24XX_TMF_TARGET_RESET 0x00000002 +#define ISP24XX_TMF_CLEAR_ACA 0x00000001 + /* I/O Abort Structure */ typedef struct { isphdr_t abrt_header; @@ -546,7 +583,9 @@ typedef struct { uint8_t abrt_vpidx; uint8_t abrt_reserved1[12]; } isp24xx_abrt_t; -#define ISP24XX_ABRT_NO_ABTS 0x01 /* don't actually send an ABTS */ + +#define ISP24XX_ABRT_NOSEND 0x01 /* don't actually send ABTS */ +#define ISP24XX_ABRT_OKAY 0x00 /* in nphdl on return */ #define ISP24XX_ABRT_ENXIO 0x31 /* in nphdl on return */ #define ISP_CDSEG 7 @@ -623,11 +662,12 @@ typedef struct { uint16_t ctp_status; uint16_t ctp_nphdl; /* n-port handle */ uint16_t ctp_cmd_cnt; /* Command DSD count */ - uint16_t ctp_vpidx; /* low 8 bits */ + uint8_t ctp_vpidx; + uint8_t ctp_reserved0; uint16_t ctp_time; - uint16_t ctp_reserved0; + uint16_t ctp_reserved1; uint16_t ctp_rsp_cnt; /* Response DSD count */ - uint16_t ctp_reserved1[5]; + uint16_t ctp_reserved2[5]; uint32_t ctp_rsp_bcnt; /* Response byte count */ uint32_t ctp_cmd_bcnt; /* Command byte count */ ispds64_t ctp_dataseg[2]; @@ -766,24 +806,36 @@ typedef struct { * About Firmware returns an 'attribute' word in mailbox 6. * These attributes are for 2200 and 2300. */ -#define ISP_FW_ATTR_TMODE 0x01 -#define ISP_FW_ATTR_SCCLUN 0x02 -#define ISP_FW_ATTR_FABRIC 0x04 -#define ISP_FW_ATTR_CLASS2 0x08 -#define ISP_FW_ATTR_FCTAPE 0x10 -#define ISP_FW_ATTR_IP 0x20 -#define ISP_FW_ATTR_VI 0x40 -#define ISP_FW_ATTR_VI_SOLARIS 0x80 -#define ISP_FW_ATTR_2KLOGINS 0x100 /* XXX: just a guess */ +#define ISP_FW_ATTR_TMODE 0x0001 +#define ISP_FW_ATTR_SCCLUN 0x0002 +#define ISP_FW_ATTR_FABRIC 0x0004 +#define ISP_FW_ATTR_CLASS2 0x0008 +#define ISP_FW_ATTR_FCTAPE 0x0010 +#define ISP_FW_ATTR_IP 0x0020 +#define ISP_FW_ATTR_VI 0x0040 +#define ISP_FW_ATTR_VI_SOLARIS 0x0080 +#define ISP_FW_ATTR_2KLOGINS 0x0100 /* just a guess... */ /* and these are for the 2400 */ -#define ISP2400_FW_ATTR_CLASS2 (1 << 0) -#define ISP2400_FW_ATTR_IP (1 << 1) -#define ISP2400_FW_ATTR_MULTIID (1 << 2) -#define ISP2400_FW_ATTR_SB2 (1 << 3) -#define ISP2400_FW_ATTR_T10CRC (1 << 4) -#define ISP2400_FW_ATTR_VI (1 << 5) -#define ISP2400_FW_ATTR_EXPFW (1 << 13) +#define ISP2400_FW_ATTR_CLASS2 0x0001 +#define ISP2400_FW_ATTR_IP 0x0002 +#define ISP2400_FW_ATTR_MULTIID 0x0004 +#define ISP2400_FW_ATTR_SB2 0x0008 +#define ISP2400_FW_ATTR_T10CRC 0x0010 +#define ISP2400_FW_ATTR_VI 0x0020 +#define ISP2400_FW_ATTR_EXPFW 0x2000 + +#define ISP_CAP_TMODE(isp) \ + (IS_24XX(isp)? 1 : (isp->isp_fwattr & ISP_FW_ATTR_TMODE)) +#define ISP_CAP_SCCFW(isp) \ + (IS_24XX(isp)? 1 : (isp->isp_fwattr & ISP_FW_ATTR_SCCLUN)) +#define ISP_CAP_2KLOGIN(isp) \ + (IS_24XX(isp)? 1 : (isp->isp_fwattr & ISP_FW_ATTR_2KLOGINS)) +#define ISP_CAP_MULTI_ID(isp) \ + (IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_MULTIID) : 0) + +#define ISP_GET_VPIDX(isp, tag) \ + (ISP_CAP_MULTI_ID(isp) ? tag : 0) /* * Reduced Interrupt Operation Response Queue Entreis @@ -928,6 +980,7 @@ typedef struct { #define ICB2400_OPT3_RATE_TWOGB 0x00002000 #define ICB2400_OPT3_RATE_AUTO 0x00004000 #define ICB2400_OPT3_RATE_FOURGB 0x00006000 +#define ICB2400_OPT3_RATE_EIGHTGB 0x00008000 #define ICB2400_OPT3_ENA_OOF_XFRDY 0x00000200 #define ICB2400_OPT3_NO_LOCAL_PLOGI 0x00000080 #define ICB2400_OPT3_ENA_OOF 0x00000040 @@ -1021,6 +1074,95 @@ typedef struct { ((uint64_t) array[ICB_NNM6] << 48) | \ ((uint64_t) array[ICB_NNM7] << 56) + +/* + * For MULTI_ID firmware, this describes a + * virtual port entity for getting status. + */ +typedef struct { + uint16_t vp_port_status; + uint8_t vp_port_options; + uint8_t vp_port_loopid; + uint8_t vp_port_portname[8]; + uint8_t vp_port_nodename[8]; + uint16_t vp_port_portid_lo; /* not present when trailing icb */ + uint16_t vp_port_portid_hi; /* not present when trailing icb */ +} vp_port_info_t; + +#define ICB2400_VPOPT_TGT_DISABLE 0x00000020 /* disable target mode */ +#define ICB2400_VPOPT_INI_ENABLE 0x00000010 /* enable initiator mode */ +#define ICB2400_VPOPT_ENABLED 0x00000008 +#define ICB2400_VPOPT_NOPLAY 0x00000004 +#define ICB2400_VPOPT_PREVLOOP 0x00000002 +#define ICB2400_VPOPT_HARD_ADDRESS 0x00000001 + +#define ICB2400_VPOPT_WRITE_SIZE 20 + +/* + * For MULTI_ID firmware, we append this structure + * to the isp_icb_2400_t above, followed by a list + * structures that are *most* of the vp_port_info_t. + */ +typedef struct { + uint16_t vp_count; + uint16_t vp_global_options; +} isp_icb_2400_vpinfo_t; + +#define ICB2400_VPINFO_OFF 0x80 /* offset from start of ICB */ +#define ICB2400_VPINFO_PORT_OFF(chan) \ + ICB2400_VPINFO_OFF + \ + sizeof (isp_icb_2400_vpinfo_t) + ((chan - 1) * ICB2400_VPOPT_WRITE_SIZE) + +#define ICB2400_VPGOPT_MID_DISABLE 0x02 + +typedef struct { + isphdr_t vp_ctrl_hdr; + uint32_t vp_ctrl_handle; + uint16_t vp_ctrl_index_fail; + uint16_t vp_ctrl_status; + uint16_t vp_ctrl_command; + uint16_t vp_ctrl_vp_count; + uint16_t vp_ctrl_idmap[8]; + uint8_t vp_ctrl_reserved[32]; +} vp_ctrl_info_t; + +#define VP_CTRL_CMD_ENABLE_VP 0 +#define VP_CTRL_CMD_DISABLE_VP 8 +#define VP_CTRL_CMD_DISABLE_VP_REINIT_LINK 9 +#define VP_CTRL_CMD_DISABLE_VP_LOGO 0xA + +/* + * We can use this structure for modifying either one or two VP ports after initialization + */ +typedef struct { + isphdr_t vp_mod_hdr; + uint32_t vp_mod_hdl; + uint16_t vp_mod_reserved0; + uint16_t vp_mod_status; + uint8_t vp_mod_cmd; + uint8_t vp_mod_cnt; + uint8_t vp_mod_idx0; + uint8_t vp_mod_idx1; + struct { + uint8_t options; + uint8_t loopid; + uint16_t reserved1; + uint8_t wwpn[8]; + uint8_t wwnn[8]; + } vp_mod_ports[2]; + uint8_t vp_mod_reserved2[8]; +} vp_modify_t; + +#define VP_STS_OK 0x00 +#define VP_STS_ERR 0x01 +#define VP_CNT_ERR 0x02 +#define VP_GEN_ERR 0x03 +#define VP_IDX_ERR 0x04 +#define VP_STS_BSY 0x05 + +#define VP_MODIFY_VP 0x00 +#define VP_MODIFY_ENA 0x01 + /* * Port Data Base Element */ @@ -1120,6 +1262,14 @@ typedef struct { #define PDB2400_CLASS2 0x0010 #define PDB2400_ADDR_VALID 0x0002 +#define PDB2400_STATE_PLOGI_PEND 0x03 +#define PDB2400_STATE_PLOGI_DONE 0x04 +#define PDB2400_STATE_PRLI_PEND 0x05 +#define PDB2400_STATE_LOGGED_IN 0x06 +#define PDB2400_STATE_PORT_UNAVAIL 0x07 +#define PDB2400_STATE_PRLO_PEND 0x09 +#define PDB2400_STATE_LOGO_PEND 0x0B + /* * Common elements from the above two structures that are actually useful to us. */ @@ -1132,11 +1282,41 @@ typedef struct { uint8_t nodename[8]; } isp_pdb_t; +/* + * Port Database Changed Async Event information for 24XX cards + */ +#define PDB24XX_AE_OK 0x00 +#define PDB24XX_AE_IMPL_LOGO_1 0x01 +#define PDB24XX_AE_IMPL_LOGO_2 0x02 +#define PDB24XX_AE_IMPL_LOGO_3 0x03 +#define PDB24XX_AE_PLOGI_RCVD 0x04 +#define PDB24XX_AE_PLOGI_RJT 0x05 +#define PDB24XX_AE_PRLI_RCVD 0x06 +#define PDB24XX_AE_PRLI_RJT 0x07 +#define PDB24XX_AE_TPRLO 0x08 +#define PDB24XX_AE_TPRLO_RJT 0x09 +#define PDB24XX_AE_PRLO_RCVD 0x0a +#define PDB24XX_AE_LOGO_RCVD 0x0b +#define PDB24XX_AE_TOPO_CHG 0x0c +#define PDB24XX_AE_NPORT_CHG 0x0d +#define PDB24XX_AE_FLOGI_RJT 0x0e +#define PDB24XX_AE_BAD_FANN 0x0f +#define PDB24XX_AE_FLOGI_TIMO 0x10 +#define PDB24XX_AE_ABX_LOGO 0x11 +#define PDB24XX_AE_PLOGI_DONE 0x12 +#define PDB24XX_AE_PRLI_DONJE 0x13 +#define PDB24XX_AE_OPN_1 0x14 +#define PDB24XX_AE_OPN_2 0x15 +#define PDB24XX_AE_TXERR 0x16 +#define PDB24XX_AE_FORCED_LOGO 0x17 +#define PDB24XX_AE_DISC_TIMO 0x18 + /* * Genericized Port Login/Logout software structure */ typedef struct { uint16_t handle; + uint16_t channel; uint32_t flags : 8, portid : 24; @@ -1200,6 +1380,36 @@ typedef struct { #define PLOGX_FLG_CLASS2 0x100 /* if with PLOGI */ #define PLOGX_FLG_FCP2_OVERRIDE 0x200 /* if with PRLOG, PRLI */ +/* + * Report ID Acquisistion (24XX multi-id firmware) + */ +typedef struct { + isphdr_t ridacq_hdr; + uint32_t ridacq_handle; + union { + struct { + uint8_t ridacq_vp_acquired; + uint8_t ridacq_vp_setup; + uint16_t ridacq_reserved0; + } type0; /* type 0 */ + struct { + uint16_t ridacq_vp_count; + uint8_t ridacq_vp_index; + uint8_t ridacq_vp_status; + } type1; /* type 1 */ + } un; + uint16_t ridacq_vp_port_lo; + uint8_t ridacq_vp_port_hi; + uint8_t ridacq_format; /* 0 or 1 */ + uint16_t ridacq_map[8]; + uint8_t ridacq_reserved1[32]; +} isp_ridacq_t; + +#define RIDACQ_STS_COMPLETE 0 +#define RIDACQ_STS_UNACQUIRED 1 +#define RIDACQ_STS_CHANGED 20 + + /* * Simple Name Server Data Structures */ @@ -1385,18 +1595,21 @@ typedef struct { } els_t; /* - * A handy package structure for running FC-SCSI commands via RUN IOCB A64. + * A handy package structure for running FC-SCSI commands internally */ typedef struct { uint16_t handle; uint16_t lun; - uint32_t portid; + uint32_t + channel : 8, + portid : 24; uint32_t timeout; union { struct { uint32_t data_length; - uint8_t do_read; - uint8_t pad[3]; + uint32_t + no_wait : 1, + do_read : 1; uint8_t cdb[16]; void *data_ptr; } beg; @@ -1409,4 +1622,923 @@ typedef struct { } end; } fcd; } isp_xcmd_t; + +/* + * Target Mode related definitions + */ +#define QLTM_SENSELEN 18 /* non-FC cards only */ +#define QLTM_SVALID 0x80 + +/* + * Structure for Enable Lun and Modify Lun queue entries + */ +typedef struct { + isphdr_t le_header; + uint32_t le_reserved; + uint8_t le_lun; + uint8_t le_rsvd; + uint8_t le_ops; /* Modify LUN only */ + uint8_t le_tgt; /* Not for FC */ + uint32_t le_flags; /* Not for FC */ + uint8_t le_status; + uint8_t le_reserved2; + uint8_t le_cmd_count; + uint8_t le_in_count; + uint8_t le_cdb6len; /* Not for FC */ + uint8_t le_cdb7len; /* Not for FC */ + uint16_t le_timeout; + uint16_t le_reserved3[20]; +} lun_entry_t; + +/* + * le_flags values + */ +#define LUN_TQAE 0x00000002 /* bit1 Tagged Queue Action Enable */ +#define LUN_DSSM 0x01000000 /* bit24 Disable Sending SDP Message */ +#define LUN_DISAD 0x02000000 /* bit25 Disable autodisconnect */ +#define LUN_DM 0x40000000 /* bit30 Disconnects Mandatory */ + +/* + * le_ops values + */ +#define LUN_CCINCR 0x01 /* increment command count */ +#define LUN_CCDECR 0x02 /* decrement command count */ +#define LUN_ININCR 0x40 /* increment immed. notify count */ +#define LUN_INDECR 0x80 /* decrement immed. notify count */ + +/* + * le_status values + */ +#define LUN_OK 0x01 /* we be rockin' */ +#define LUN_ERR 0x04 /* request completed with error */ +#define LUN_INVAL 0x06 /* invalid request */ +#define LUN_NOCAP 0x16 /* can't provide requested capability */ +#define LUN_ENABLED 0x3E /* LUN already enabled */ + +/* + * Immediate Notify Entry structure + */ +#define IN_MSGLEN 8 /* 8 bytes */ +#define IN_RSVDLEN 8 /* 8 words */ +typedef struct { + isphdr_t in_header; + uint32_t in_reserved; + uint8_t in_lun; /* lun */ + uint8_t in_iid; /* initiator */ + uint8_t in_reserved2; + uint8_t in_tgt; /* target */ + uint32_t in_flags; + uint8_t in_status; + uint8_t in_rsvd2; + uint8_t in_tag_val; /* tag value */ + uint8_t in_tag_type; /* tag type */ + uint16_t in_seqid; /* sequence id */ + uint8_t in_msg[IN_MSGLEN]; /* SCSI message bytes */ + uint16_t in_reserved3[IN_RSVDLEN]; + uint8_t in_sense[QLTM_SENSELEN];/* suggested sense data */ +} in_entry_t; + +typedef struct { + isphdr_t in_header; + uint32_t in_reserved; + uint8_t in_lun; /* lun */ + uint8_t in_iid; /* initiator */ + uint16_t in_scclun; + uint32_t in_reserved2; + uint16_t in_status; + uint16_t in_task_flags; + uint16_t in_seqid; /* sequence id */ +} in_fcentry_t; + +typedef struct { + isphdr_t in_header; + uint32_t in_reserved; + uint16_t in_iid; /* initiator */ + uint16_t in_scclun; + uint32_t in_reserved2; + uint16_t in_status; + uint16_t in_task_flags; + uint16_t in_seqid; /* sequence id */ +} in_fcentry_e_t; + +/* + * Values for the in_status field + */ +#define IN_REJECT 0x0D /* Message Reject message received */ +#define IN_RESET 0x0E /* Bus Reset occurred */ +#define IN_NO_RCAP 0x16 /* requested capability not available */ +#define IN_IDE_RECEIVED 0x33 /* Initiator Detected Error msg received */ +#define IN_RSRC_UNAVAIL 0x34 /* resource unavailable */ +#define IN_MSG_RECEIVED 0x36 /* SCSI message received */ +#define IN_ABORT_TASK 0x20 /* task named in RX_ID is being aborted (FC) */ +#define IN_PORT_LOGOUT 0x29 /* port has logged out (FC) */ +#define IN_PORT_CHANGED 0x2A /* port changed */ +#define IN_GLOBAL_LOGO 0x2E /* all ports logged out */ +#define IN_NO_NEXUS 0x3B /* Nexus not established */ + +/* + * Values for the in_task_flags field- should only get one at a time! + */ +#define TASK_FLAGS_RESERVED_MASK (0xe700) +#define TASK_FLAGS_CLEAR_ACA (1<<14) +#define TASK_FLAGS_TARGET_RESET (1<<13) +#define TASK_FLAGS_LUN_RESET (1<<12) +#define TASK_FLAGS_CLEAR_TASK_SET (1<<10) +#define TASK_FLAGS_ABORT_TASK_SET (1<<9) + +/* + * ISP24XX Immediate Notify + */ +typedef struct { + isphdr_t in_header; + uint32_t in_reserved; + uint16_t in_nphdl; + uint16_t in_reserved1; + uint16_t in_flags; + uint16_t in_srr_rxid; + uint16_t in_status; + uint8_t in_status_subcode; + uint8_t in_reserved2; + uint32_t in_rxid; + uint16_t in_srr_reloff_lo; + uint16_t in_srr_reloff_hi; + uint16_t in_srr_iu; + uint16_t in_srr_oxid; + /* + * If bit 2 is set in in_flags, the following + * two tags are valid. If the received ELS is + * a LOGO, then these tags contain the N Port ID + * from the LOGO payload. If the received ELS + * request is TPRLO, these tags contain the + * Third Party Originator N Port ID. + */ + uint16_t in_nport_id_hi; + uint8_t in_nport_id_lo; + uint8_t in_reserved3; + /* + * If bit 2 is set in in_flags, the following + * tag is valid. If the received ELS is a LOGO, + * then this tag contains the n-port handle + * from the LOGO payload. If the received ELS + * request is TPRLO, this tag contain the + * n-port handle for the Third Party Originator. + */ + uint16_t in_np_handle; + uint8_t in_reserved4[12]; + uint8_t in_reserved5; + uint8_t in_vpidx; + uint32_t in_reserved6; + uint16_t in_portid_lo; + uint8_t in_portid_hi; + uint8_t in_reserved7; + uint16_t in_reserved8; + uint16_t in_oxid; +} in_fcentry_24xx_t; + +#define IN24XX_FLAG_PUREX_IOCB 0x1 +#define IN24XX_FLAG_GLOBAL_LOGOUT 0x2 +#define IN24XX_FLAG_NPHDL_VALID 0x4 + +#define IN24XX_LIP_RESET 0x0E +#define IN24XX_LINK_RESET 0x0F +#define IN24XX_PORT_LOGOUT 0x29 +#define IN24XX_PORT_CHANGED 0x2A +#define IN24XX_LINK_FAILED 0x2E +#define IN24XX_SRR_RCVD 0x45 +#define IN24XX_ELS_RCVD 0x46 /* + * login-affectin ELS received- check + * subcode for specific opcode + */ + +/* + * For f/w > 4.0.25, these offsets in the Immediate Notify contain + * the WWNN/WWPN if the ELS is PLOGI, PDISC or ADISC. The WWN is in + * Big Endian format. + */ +#define IN24XX_PLOGI_WWNN_OFF 0x20 +#define IN24XX_PLOGI_WWPN_OFF 0x28 + +/* + * For f/w > 4.0.25, this offset in the Immediate Notify contain + * the WWPN if the ELS is LOGO. The WWN is in Big Endian format. + */ +#define IN24XX_LOGO_WWPN_OFF 0x28 + +/* + * Immediate Notify Status Subcodes for IN24XX_PORT_LOGOUT + */ +#define IN24XX_PORT_LOGOUT_PDISC_TMO 0x00 +#define IN24XX_PORT_LOGOUT_UXPR_DISC 0x01 +#define IN24XX_PORT_LOGOUT_OWN_OPN 0x02 +#define IN24XX_PORT_LOGOUT_OWN_OPN_SFT 0x03 +#define IN24XX_PORT_LOGOUT_ABTS_TMO 0x04 +#define IN24XX_PORT_LOGOUT_DISC_RJT 0x05 +#define IN24XX_PORT_LOGOUT_LOGIN_NEEDED 0x06 +#define IN24XX_PORT_LOGOUT_BAD_DISC 0x07 +#define IN24XX_PORT_LOGOUT_LOST_ALPA 0x08 +#define IN24XX_PORT_LOGOUT_XMIT_FAILURE 0x09 + +/* + * Immediate Notify Status Subcodes for IN24XX_PORT_CHANGED + */ +#define IN24XX_PORT_CHANGED_BADFAN 0x00 +#define IN24XX_PORT_CHANGED_TOPO_CHANGE 0x01 +#define IN24XX_PORT_CHANGED_FLOGI_ACC 0x02 +#define IN24XX_PORT_CHANGED_FLOGI_RJT 0x03 +#define IN24XX_PORT_CHANGED_TIMEOUT 0x04 +#define IN24XX_PORT_CHANGED_PORT_CHANGE 0x05 + +/* + * Notify Acknowledge Entry structure + */ +#define NA_RSVDLEN 22 +typedef struct { + isphdr_t na_header; + uint32_t na_reserved; + uint8_t na_lun; /* lun */ + uint8_t na_iid; /* initiator */ + uint8_t na_reserved2; + uint8_t na_tgt; /* target */ + uint32_t na_flags; + uint8_t na_status; + uint8_t na_event; + uint16_t na_seqid; /* sequence id */ + uint16_t na_reserved3[NA_RSVDLEN]; +} na_entry_t; + +/* + * Value for the na_event field + */ +#define NA_RST_CLRD 0x80 /* Clear an async event notification */ +#define NA_OK 0x01 /* Notify Acknowledge Succeeded */ +#define NA_INVALID 0x06 /* Invalid Notify Acknowledge */ + +#define NA2_RSVDLEN 21 +typedef struct { + isphdr_t na_header; + uint32_t na_reserved; + uint8_t na_reserved1; + uint8_t na_iid; /* initiator loop id */ + uint16_t na_response; + uint16_t na_flags; + uint16_t na_reserved2; + uint16_t na_status; + uint16_t na_task_flags; + uint16_t na_seqid; /* sequence id */ + uint16_t na_reserved3[NA2_RSVDLEN]; +} na_fcentry_t; + +typedef struct { + isphdr_t na_header; + uint32_t na_reserved; + uint16_t na_iid; /* initiator loop id */ + uint16_t na_response; /* response code */ + uint16_t na_flags; + uint16_t na_reserved2; + uint16_t na_status; + uint16_t na_task_flags; + uint16_t na_seqid; /* sequence id */ + uint16_t na_reserved3[NA2_RSVDLEN]; +} na_fcentry_e_t; + +#define NAFC_RCOUNT 0x80 /* increment resource count */ +#define NAFC_RST_CLRD 0x20 /* Clear LIP Reset */ +#define NAFC_TVALID 0x10 /* task mangement response code is valid */ + +/* + * ISP24XX Notify Acknowledge + */ + +typedef struct { + isphdr_t na_header; + uint32_t na_handle; + uint16_t na_nphdl; + uint16_t na_reserved1; + uint16_t na_flags; + uint16_t na_srr_rxid; + uint16_t na_status; + uint8_t na_status_subcode; + uint8_t na_reserved2; + uint32_t na_rxid; + uint16_t na_srr_reloff_lo; + uint16_t na_srr_reloff_hi; + uint16_t na_srr_iu; + uint16_t na_srr_flags; + uint8_t na_reserved3[18]; + uint8_t na_reserved4; + uint8_t na_vpidx; + uint8_t na_srr_reject_vunique; + uint8_t na_srr_reject_explanation; + uint8_t na_srr_reject_code; + uint8_t na_reserved5; + uint8_t na_reserved6[6]; + uint16_t na_oxid; +} na_fcentry_24xx_t; + +/* + * Accept Target I/O Entry structure + */ +#define ATIO_CDBLEN 26 + +typedef struct { + isphdr_t at_header; + uint16_t at_reserved; + uint16_t at_handle; + uint8_t at_lun; /* lun */ + uint8_t at_iid; /* initiator */ + uint8_t at_cdblen; /* cdb length */ + uint8_t at_tgt; /* target */ + uint32_t at_flags; + uint8_t at_status; /* firmware status */ + uint8_t at_scsi_status; /* scsi status */ + uint8_t at_tag_val; /* tag value */ + uint8_t at_tag_type; /* tag type */ + uint8_t at_cdb[ATIO_CDBLEN]; /* received CDB */ + uint8_t at_sense[QLTM_SENSELEN];/* suggested sense data */ +} at_entry_t; + +/* + * at_flags values + */ +#define AT_NODISC 0x00008000 /* disconnect disabled */ +#define AT_TQAE 0x00000002 /* Tagged Queue Action enabled */ + +/* + * at_status values + */ +#define AT_PATH_INVALID 0x07 /* ATIO sent to firmware for disabled lun */ +#define AT_RESET 0x0E /* SCSI Bus Reset Occurred */ +#define AT_PHASE_ERROR 0x14 /* Bus phase sequence error */ +#define AT_NOCAP 0x16 /* Requested capability not available */ +#define AT_BDR_MSG 0x17 /* Bus Device Reset msg received */ +#define AT_CDB 0x3D /* CDB received */ +/* + * Macros to create and fetch and test concatenated handle and tag value macros + * (SPI only) + */ +#define AT_MAKE_TAGID(tid, aep) \ + tid = aep->at_handle; \ + if (aep->at_flags & AT_TQAE) { \ + tid |= (aep->at_tag_val << 16); \ + tid |= (1 << 24); \ + } + +#define CT_MAKE_TAGID(tid, ct) \ + tid = ct->ct_fwhandle; \ + if (ct->ct_flags & CT_TQAE) { \ + tid |= (ct->ct_tag_val << 16); \ + tid |= (1 << 24); \ + } + +#define AT_HAS_TAG(val) ((val) & (1 << 24)) +#define AT_GET_TAG(val) (((val) >> 16) & 0xff) +#define AT_GET_HANDLE(val) ((val) & 0xffff) + +#define IN_MAKE_TAGID(tid, inp) \ + tid = inp->in_seqid; \ + tid |= (inp->in_tag_val << 16); \ + tid |= (1 << 24) + +/* + * Accept Target I/O Entry structure, Type 2 + */ +#define ATIO2_CDBLEN 16 + +typedef struct { + isphdr_t at_header; + uint32_t at_reserved; + uint8_t at_lun; /* lun or reserved */ + uint8_t at_iid; /* initiator */ + uint16_t at_rxid; /* response ID */ + uint16_t at_flags; + uint16_t at_status; /* firmware status */ + uint8_t at_crn; /* command reference number */ + uint8_t at_taskcodes; + uint8_t at_taskflags; + uint8_t at_execodes; + uint8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */ + uint32_t at_datalen; /* allocated data len */ + uint16_t at_scclun; /* SCC Lun or reserved */ + uint16_t at_wwpn[4]; /* WWPN of initiator */ + uint16_t at_reserved2[6]; + uint16_t at_oxid; +} at2_entry_t; + +typedef struct { + isphdr_t at_header; + uint32_t at_reserved; + uint16_t at_iid; /* initiator */ + uint16_t at_rxid; /* response ID */ + uint16_t at_flags; + uint16_t at_status; /* firmware status */ + uint8_t at_crn; /* command reference number */ + uint8_t at_taskcodes; + uint8_t at_taskflags; + uint8_t at_execodes; + uint8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */ + uint32_t at_datalen; /* allocated data len */ + uint16_t at_scclun; /* SCC Lun or reserved */ + uint16_t at_wwpn[4]; /* WWPN of initiator */ + uint16_t at_reserved2[6]; + uint16_t at_oxid; +} at2e_entry_t; + +#define ATIO2_WWPN_OFFSET 0x2A +#define ATIO2_OXID_OFFSET 0x3E + +#define ATIO2_TC_ATTR_MASK 0x7 +#define ATIO2_TC_ATTR_SIMPLEQ 0 +#define ATIO2_TC_ATTR_HEADOFQ 1 +#define ATIO2_TC_ATTR_ORDERED 2 +#define ATIO2_TC_ATTR_ACAQ 4 +#define ATIO2_TC_ATTR_UNTAGGED 5 + +#define ATIO2_EX_WRITE 0x1 +#define ATIO2_EX_READ 0x2 +/* + * Macros to create and fetch and test concatenated handle and tag value macros + */ +#define AT2_MAKE_TAGID(tid, bus, inst, aep) \ + tid = aep->at_rxid; \ + tid |= (((uint64_t)inst) << 32); \ + tid |= (((uint64_t)bus) << 48) + +#define CT2_MAKE_TAGID(tid, bus, inst, ct) \ + tid = ct->ct_rxid; \ + tid |= (((uint64_t)inst) << 32); \ + tid |= (((uint64_t)(bus & 0xff)) << 48) + +#define AT2_HAS_TAG(val) 1 +#define AT2_GET_TAG(val) ((val) & 0xffffffff) +#define AT2_GET_INST(val) (((val) >> 32) & 0xffff) +#define AT2_GET_HANDLE AT2_GET_TAG +#define AT2_GET_BUS(val) (((val) >> 48) & 0xff) + +#define FC_HAS_TAG AT2_HAS_TAG +#define FC_GET_TAG AT2_GET_TAG +#define FC_GET_INST AT2_GET_INST +#define FC_GET_HANDLE AT2_GET_HANDLE + +#define IN_FC_MAKE_TAGID(tid, bus, inst, seqid) \ + tid = seqid; \ + tid |= (((uint64_t)inst) << 32); \ + tid |= (((uint64_t)(bus & 0xff)) << 48) + +#define FC_TAG_INSERT_INST(tid, inst) \ + tid &= ~0x0000ffff00000000ull; \ + tid |= (((uint64_t)inst) << 32) + +/* + * 24XX ATIO Definition + * + * This is *quite* different from other entry types. + * First of all, it has its own queue it comes in on. + * + * Secondly, it doesn't have a normal header. + * + * Thirdly, it's just a passthru of the FCP CMND IU + * which is recorded in big endian mode. + */ +typedef struct { + uint8_t at_type; + uint8_t at_count; + /* + * Task attribute in high four bits, + * the rest is the FCP CMND IU Length. + * NB: the command can extend past the + * length for a single queue entry. + */ + uint16_t at_ta_len; + uint32_t at_rxid; + fc_hdr_t at_hdr; + fcp_cmnd_iu_t at_cmnd; +} at7_entry_t; +#define AT7_NORESRC_RXID 0xffffffff + + +/* + * Continue Target I/O Entry structure + * Request from driver. The response from the + * ISP firmware is the same except that the last 18 + * bytes are overwritten by suggested sense data if + * the 'autosense valid' bit is set in the status byte. + */ +typedef struct { + isphdr_t ct_header; + uint16_t ct_syshandle; + uint16_t ct_fwhandle; /* required by f/w */ + uint8_t ct_lun; /* lun */ + uint8_t ct_iid; /* initiator id */ + uint8_t ct_reserved2; + uint8_t ct_tgt; /* our target id */ + uint32_t ct_flags; + uint8_t ct_status; /* isp status */ + uint8_t ct_scsi_status; /* scsi status */ + uint8_t ct_tag_val; /* tag value */ + uint8_t ct_tag_type; /* tag type */ + uint32_t ct_xfrlen; /* transfer length */ + int32_t ct_resid; /* residual length */ + uint16_t ct_timeout; + uint16_t ct_seg_count; + ispds_t ct_dataseg[ISP_RQDSEG]; +} ct_entry_t; + +/* + * For some of the dual port SCSI adapters, port (bus #) is reported + * in the MSbit of ct_iid. Bit fields are a bit too awkward here. + * + * Note that this does not apply to FC adapters at all which can and + * do report IIDs between 0x81 && 0xfe (or 0x7ff) which represent devices + * that have logged in across a SCSI fabric. + */ +#define GET_IID_VAL(x) (x & 0x3f) +#define GET_BUS_VAL(x) ((x >> 7) & 0x1) +#define SET_IID_VAL(y, x) y = ((y & ~0x3f) | (x & 0x3f)) +#define SET_BUS_VAL(y, x) y = ((y & 0x3f) | ((x & 0x1) << 7)) + +/* + * ct_flags values + */ +#define CT_TQAE 0x00000002 /* bit 1, Tagged Queue Action enable */ +#define CT_DATA_IN 0x00000040 /* bits 6&7, Data direction */ +#define CT_DATA_OUT 0x00000080 /* bits 6&7, Data direction */ +#define CT_NO_DATA 0x000000C0 /* bits 6&7, Data direction */ +#define CT_CCINCR 0x00000100 /* bit 8, autoincrement atio count */ +#define CT_DATAMASK 0x000000C0 /* bits 6&7, Data direction */ +#define CT_INISYNCWIDE 0x00004000 /* bit 14, Do Sync/Wide Negotiation */ +#define CT_NODISC 0x00008000 /* bit 15, Disconnects disabled */ +#define CT_DSDP 0x01000000 /* bit 24, Disable Save Data Pointers */ +#define CT_SENDRDP 0x04000000 /* bit 26, Send Restore Pointers msg */ +#define CT_SENDSTATUS 0x80000000 /* bit 31, Send SCSI status byte */ + +/* + * ct_status values + * - set by the firmware when it returns the CTIO + */ +#define CT_OK 0x01 /* completed without error */ +#define CT_ABORTED 0x02 /* aborted by host */ +#define CT_ERR 0x04 /* see sense data for error */ +#define CT_INVAL 0x06 /* request for disabled lun */ +#define CT_NOPATH 0x07 /* invalid ITL nexus */ +#define CT_INVRXID 0x08 /* (FC only) Invalid RX_ID */ +#define CT_DATA_OVER 0x09 /* (FC only) Data Overrun */ +#define CT_RSELTMO 0x0A /* reselection timeout after 2 tries */ +#define CT_TIMEOUT 0x0B /* timed out */ +#define CT_RESET 0x0E /* SCSI Bus Reset occurred */ +#define CT_PARITY 0x0F /* Uncorrectable Parity Error */ +#define CT_BUS_ERROR 0x10 /* (FC Only) DMA PCI Error */ +#define CT_PANIC 0x13 /* Unrecoverable Error */ +#define CT_PHASE_ERROR 0x14 /* Bus phase sequence error */ +#define CT_DATA_UNDER 0x15 /* (FC only) Data Underrun */ +#define CT_BDR_MSG 0x17 /* Bus Device Reset msg received */ +#define CT_TERMINATED 0x19 /* due to Terminate Transfer mbox cmd */ +#define CT_PORTUNAVAIL 0x28 /* port not available */ +#define CT_LOGOUT 0x29 /* port logout */ +#define CT_PORTCHANGED 0x2A /* port changed */ +#define CT_IDE 0x33 /* Initiator Detected Error */ +#define CT_NOACK 0x35 /* Outstanding Immed. Notify. entry */ +#define CT_SRR 0x45 /* SRR Received */ +#define CT_LUN_RESET 0x48 /* Lun Reset Received */ + +#define CT_HBA_RESET 0xffff /* pseudo error - command destroyed by HBA reset*/ + +/* + * When the firmware returns a CTIO entry, it may overwrite the last + * part of the structure with sense data. This starts at offset 0x2E + * into the entry, which is in the middle of ct_dataseg[1]. Rather + * than define a new struct for this, I'm just using the sense data + * offset. + */ +#define CTIO_SENSE_OFFSET 0x2E + +/* + * Entry length in u_longs. All entries are the same size so + * any one will do as the numerator. + */ +#define UINT32_ENTRY_SIZE (sizeof(at_entry_t)/sizeof(uint32_t)) + +/* + * QLA2100 CTIO (type 2) entry + */ +#define MAXRESPLEN 26 +typedef struct { + isphdr_t ct_header; + uint32_t ct_syshandle; + uint8_t ct_lun; /* lun */ + uint8_t ct_iid; /* initiator id */ + uint16_t ct_rxid; /* response ID */ + uint16_t ct_flags; + uint16_t ct_status; /* isp status */ + uint16_t ct_timeout; + uint16_t ct_seg_count; + uint32_t ct_reloff; /* relative offset */ + int32_t ct_resid; /* residual length */ + union { + /* + * The three different modes that the target driver + * can set the CTIO{2,3,4} up as. + * + * The first is for sending FCP_DATA_IUs as well as + * (optionally) sending a terminal SCSI status FCP_RSP_IU. + * + * The second is for sending SCSI sense data in an FCP_RSP_IU. + * Note that no FCP_DATA_IUs will be sent. + * + * The third is for sending FCP_RSP_IUs as built specifically + * in system memory as located by the isp_dataseg. + */ + struct { + uint32_t _reserved; + uint16_t _reserved2; + uint16_t ct_scsi_status; + uint32_t ct_xfrlen; + union { + ispds_t ct_dataseg[ISP_RQDSEG_T2]; + ispds64_t ct_dataseg64[ISP_RQDSEG_T3]; + ispdslist_t ct_dslist; + } u; + } m0; + struct { + uint16_t _reserved; + uint16_t _reserved2; + uint16_t ct_senselen; + uint16_t ct_scsi_status; + uint16_t ct_resplen; + uint8_t ct_resp[MAXRESPLEN]; + } m1; + struct { + uint32_t _reserved; + uint16_t _reserved2; + uint16_t _reserved3; + uint32_t ct_datalen; + ispds_t ct_fcp_rsp_iudata; + } m2; + } rsp; +} ct2_entry_t; + +typedef struct { + isphdr_t ct_header; + uint32_t ct_syshandle; + uint16_t ct_iid; /* initiator id */ + uint16_t ct_rxid; /* response ID */ + uint16_t ct_flags; + uint16_t ct_status; /* isp status */ + uint16_t ct_timeout; + uint16_t ct_seg_count; + uint32_t ct_reloff; /* relative offset */ + int32_t ct_resid; /* residual length */ + union { + struct { + uint32_t _reserved; + uint16_t _reserved2; + uint16_t ct_scsi_status; + uint32_t ct_xfrlen; + union { + ispds_t ct_dataseg[ISP_RQDSEG_T2]; + ispds64_t ct_dataseg64[ISP_RQDSEG_T3]; + ispdslist_t ct_dslist; + } u; + } m0; + struct { + uint16_t _reserved; + uint16_t _reserved2; + uint16_t ct_senselen; + uint16_t ct_scsi_status; + uint16_t ct_resplen; + uint8_t ct_resp[MAXRESPLEN]; + } m1; + struct { + uint32_t _reserved; + uint16_t _reserved2; + uint16_t _reserved3; + uint32_t ct_datalen; + ispds_t ct_fcp_rsp_iudata; + } m2; + } rsp; +} ct2e_entry_t; + +/* + * ct_flags values for CTIO2 + */ +#define CT2_FLAG_MODE0 0x0000 +#define CT2_FLAG_MODE1 0x0001 +#define CT2_FLAG_MODE2 0x0002 +#define CT2_FLAG_MMASK 0x0003 +#define CT2_DATA_IN 0x0040 +#define CT2_DATA_OUT 0x0080 +#define CT2_NO_DATA 0x00C0 +#define CT2_DATAMASK 0x00C0 +#define CT2_CCINCR 0x0100 +#define CT2_FASTPOST 0x0200 +#define CT2_CONFIRM 0x2000 +#define CT2_TERMINATE 0x4000 +#define CT2_SENDSTATUS 0x8000 + +/* + * ct_status values are (mostly) the same as that for ct_entry. + */ + +/* + * ct_scsi_status values- the low 8 bits are the normal SCSI status + * we know and love. The upper 8 bits are validity markers for FCP_RSP_IU + * fields. + */ +#define CT2_RSPLEN_VALID 0x0100 +#define CT2_SNSLEN_VALID 0x0200 +#define CT2_DATA_OVER 0x0400 +#define CT2_DATA_UNDER 0x0800 + +/* + * ISP24XX CTIO + */ +#define MAXRESPLEN_24XX 24 +typedef struct { + isphdr_t ct_header; + uint32_t ct_syshandle; + uint16_t ct_nphdl; /* status on returned CTIOs */ + uint16_t ct_timeout; + uint16_t ct_seg_count; + uint8_t ct_vpidx; + uint8_t ct_xflags; + uint16_t ct_iid_lo; /* low 16 bits of portid */ + uint8_t ct_iid_hi; /* hi 8 bits of portid */ + uint8_t ct_reserved; + uint32_t ct_rxid; + uint16_t ct_senselen; /* mode 1 only */ + uint16_t ct_flags; + int32_t ct_resid; /* residual length */ + uint16_t ct_oxid; + uint16_t ct_scsi_status; /* modes 0 && 1 only */ + union { + struct { + uint32_t reloff; + uint32_t reserved0; + uint32_t ct_xfrlen; + uint32_t reserved1; + ispds64_t ds; + } m0; + struct { + uint16_t ct_resplen; + uint16_t reserved; + uint8_t ct_resp[MAXRESPLEN_24XX]; + } m1; + struct { + uint32_t reserved0; + uint32_t ct_datalen; + uint32_t reserved1; + ispds64_t ct_fcp_rsp_iudata; + } m2; + } rsp; +} ct7_entry_t; + +/* + * ct_flags values for CTIO7 + */ +#define CT7_DATA_IN 0x0002 +#define CT7_DATA_OUT 0x0001 +#define CT7_NO_DATA 0x0000 +#define CT7_DATAMASK 0x003 +#define CT7_DSD_ENABLE 0x0004 +#define CT7_CONF_STSFD 0x0010 +#define CT7_EXPLCT_CONF 0x0020 +#define CT7_FLAG_MODE0 0x0000 +#define CT7_FLAG_MODE1 0x0040 +#define CT7_FLAG_MODE2 0x0080 +#define CT7_FLAG_MMASK 0x00C0 +#define CT7_NOACK 0x0100 +#define CT7_TASK_ATTR_SHIFT 9 +#define CT7_CONFIRM 0x2000 +#define CT7_TERMINATE 0x4000 +#define CT7_SENDSTATUS 0x8000 + +/* + * Type 7 CTIO status codes + */ +#define CT7_OK 0x01 /* completed without error */ +#define CT7_ABORTED 0x02 /* aborted by host */ +#define CT7_ERR 0x04 /* see sense data for error */ +#define CT7_INVAL 0x06 /* request for disabled lun */ +#define CT7_INVRXID 0x08 /* Invalid RX_ID */ +#define CT7_DATA_OVER 0x09 /* Data Overrun */ +#define CT7_TIMEOUT 0x0B /* timed out */ +#define CT7_RESET 0x0E /* LIP Rset Received */ +#define CT7_BUS_ERROR 0x10 /* DMA PCI Error */ +#define CT7_REASSY_ERR 0x11 /* DMA reassembly error */ +#define CT7_DATA_UNDER 0x15 /* Data Underrun */ +#define CT7_PORTUNAVAIL 0x28 /* port not available */ +#define CT7_LOGOUT 0x29 /* port logout */ +#define CT7_PORTCHANGED 0x2A /* port changed */ +#define CT7_SRR 0x45 /* SRR Received */ + +/* + * Other 24XX related target IOCBs + */ + +/* + * ABTS Received + */ +typedef struct { + isphdr_t abts_header; + uint8_t abts_reserved0[6]; + uint16_t abts_nphdl; + uint16_t abts_reserved1; + uint16_t abts_sof; + uint32_t abts_rxid_abts; + uint16_t abts_did_lo; + uint8_t abts_did_hi; + uint8_t abts_r_ctl; + uint16_t abts_sid_lo; + uint8_t abts_sid_hi; + uint8_t abts_cs_ctl; + uint16_t abts_fs_ctl; + uint8_t abts_f_ctl; + uint8_t abts_type; + uint16_t abts_seq_cnt; + uint8_t abts_df_ctl; + uint8_t abts_seq_id; + uint16_t abts_rx_id; + uint16_t abts_ox_id; + uint32_t abts_param; + uint8_t abts_reserved2[16]; + uint32_t abts_rxid_task; +} abts_t; + +typedef struct { + isphdr_t abts_rsp_header; + uint32_t abts_rsp_handle; + uint16_t abts_rsp_status; + uint16_t abts_rsp_nphdl; + uint16_t abts_rsp_ctl_flags; + uint16_t abts_rsp_sof; + uint32_t abts_rsp_rxid_abts; + uint16_t abts_rsp_did_lo; + uint8_t abts_rsp_did_hi; + uint8_t abts_rsp_r_ctl; + uint16_t abts_rsp_sid_lo; + uint8_t abts_rsp_sid_hi; + uint8_t abts_rsp_cs_ctl; + uint16_t abts_rsp_f_ctl_lo; + uint8_t abts_rsp_f_ctl_hi; + uint8_t abts_rsp_type; + uint16_t abts_rsp_seq_cnt; + uint8_t abts_rsp_df_ctl; + uint8_t abts_rsp_seq_id; + uint16_t abts_rsp_rx_id; + uint16_t abts_rsp_ox_id; + uint32_t abts_rsp_param; + union { + struct { + uint16_t reserved; + uint8_t last_seq_id; + uint8_t seq_id_valid; + uint16_t aborted_rx_id; + uint16_t aborted_ox_id; + uint16_t high_seq_cnt; + uint16_t low_seq_cnt; + uint8_t reserved2[4]; + } ba_acc; + struct { + uint8_t vendor_unique; + uint8_t explanation; + uint8_t reason; + uint8_t reserved; + uint8_t reserved2[12]; + } ba_rjt; + struct { + uint8_t reserved[8]; + uint32_t subcode1; + uint32_t subcode2; + } rsp; + uint8_t reserved[16]; + } abts_rsp_payload; + uint32_t abts_rsp_rxid_task; +} abts_rsp_t; + +/* terminate this ABTS exchange */ +#define ISP24XX_ABTS_RSP_TERMINATE 0x01 + +#define ISP24XX_ABTS_RSP_COMPLETE 0x00 +#define ISP24XX_ABTS_RSP_RESET 0x04 +#define ISP24XX_ABTS_RSP_ABORTED 0x05 +#define ISP24XX_ABTS_RSP_TIMEOUT 0x06 +#define ISP24XX_ABTS_RSP_INVXID 0x08 +#define ISP24XX_ABTS_RSP_LOGOUT 0x29 +#define ISP24XX_ABTS_RSP_SUBCODE 0x31 + +#define ISP24XX_NO_TASK 0xffffffff + +/* + * Miscellaneous + * + * These are the limits of the number of dma segments we + * can deal with based not on the size of the segment counter + * (which is 16 bits), but on the size of the number of + * queue entries field (which is 8 bits). We assume no + * segments in the first queue entry, so we can either + * have 7 dma segments per continuation entry or 5 + * (for 64 bit dma).. multiplying out by 254.... + */ +#define ISP_NSEG_MAX 1778 +#define ISP_NSEG64_MAX 1270 + #endif /* _ISPMBOX_H */ diff --git a/sys/dev/isp/ispreg.h b/sys/dev/isp/ispreg.h index ee0e154da32a..08df337b88b9 100644 --- a/sys/dev/isp/ispreg.h +++ b/sys/dev/isp/ispreg.h @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Machine Independent (well, as best as possible) register @@ -362,11 +363,12 @@ #define BIU2400_REQOUTP (BIU_BLOCK+0x20) /* Request Queue Out */ #define BIU2400_RSPINP (BIU_BLOCK+0x24) /* Response Queue In */ #define BIU2400_RSPOUTP (BIU_BLOCK+0x28) /* Response Queue Out */ -#define BIU2400_PRI_RQINP (BIU_BLOCK+0x2C) /* Priority Request Q In */ -#define BIU2400_PRI_RSPINP (BIU_BLOCK+0x30) /* Priority Request Q Out */ -#define BIU2400_ATIO_RSPINP (BIU_BLOCK+0x3C) /* ATIO Queue In */ -#define BIU2400_ATIO_REQINP (BIU_BLOCK+0x40) /* ATIO Queue Out */ +#define BIU2400_PRI_REQINP (BIU_BLOCK+0x2C) /* Priority Request Q In */ +#define BIU2400_PRI_REQOUTP (BIU_BLOCK+0x30) /* Priority Request Q Out */ + +#define BIU2400_ATIO_RSPINP (BIU_BLOCK+0x3C) /* ATIO Queue In */ +#define BIU2400_ATIO_RSPOUTP (BIU_BLOCK+0x40) /* ATIO Queue Out */ #define BIU2400_R2HSTSLO (BIU_BLOCK+0x44) #define BIU2400_R2HSTSHI (BIU_BLOCK+0x46) @@ -469,10 +471,21 @@ typedef struct { uint16_t param[MAILBOX_STORAGE]; uint16_t ibits; uint16_t obits; - uint32_t : 28, + uint32_t + lineno : 16, + : 12, logval : 4; uint32_t timeout; + const char *func; } mbreg_t; +#define MBSINIT(mbxp, code, loglev, timo) \ + ISP_MEMZERO((mbxp), sizeof (mbreg_t)); \ + (mbxp)->param[0] = code; \ + (mbxp)->lineno = __LINE__; \ + (mbxp)->func = __func__; \ + (mbxp)->logval = loglev; \ + (mbxp)->timeout = timo + /* * Fibre Protocol Module and Frame Buffer Register Offsets/Definitions (2X00). diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index 96c8b067ac21..e568a1c9b765 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -1,18 +1,18 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 1997-2007 by Matthew Jacob + * Copyright (c) 1997-2009 by Matthew Jacob * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -24,6 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * */ /* * Soft Definitions for for Qlogic ISP SCSI adapters. @@ -49,7 +50,7 @@ #include "ispmbox.h" #endif -#define ISP_CORE_VERSION_MAJOR 3 +#define ISP_CORE_VERSION_MAJOR 6 #define ISP_CORE_VERSION_MINOR 0 /* @@ -57,13 +58,11 @@ */ typedef struct ispsoftc ispsoftc_t; struct ispmdvec { - int (*dv_rd_isr) - (ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); + int (*dv_rd_isr) (ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); uint32_t (*dv_rd_reg) (ispsoftc_t *, int); void (*dv_wr_reg) (ispsoftc_t *, int, uint32_t); int (*dv_mbxdma) (ispsoftc_t *); - int (*dv_dmaset) - (ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); + int (*dv_dmaset) (ispsoftc_t *, XS_T *, void *); void (*dv_dmaclr) (ispsoftc_t *, XS_T *, uint32_t); void (*dv_reset0) (ispsoftc_t *); void (*dv_reset1) (ispsoftc_t *); @@ -77,7 +76,9 @@ struct ispmdvec { * Overall parameters */ #define MAX_TARGETS 16 +#ifndef MAX_FC_TARG #define MAX_FC_TARG 512 +#endif #define ISP_MAX_TARGETS(isp) (IS_FC(isp)? MAX_FC_TARG : MAX_TARGETS) #define ISP_MAX_LUNS(isp) (isp)->isp_maxluns @@ -97,8 +98,8 @@ struct ispmdvec { #define ISP_MBOXDMASETUP(isp) \ (*(isp)->isp_mdvec->dv_mbxdma)((isp)) -#define ISP_DMASETUP(isp, xs, req, iptrp, optr) \ - (*(isp)->isp_mdvec->dv_dmaset)((isp), (xs), (req), (iptrp), (optr)) +#define ISP_DMASETUP(isp, xs, req) \ + (*(isp)->isp_mdvec->dv_dmaset)((isp), (xs), (req)) #define ISP_DMAFREE(isp, xs, hndl) \ if ((isp)->isp_mdvec->dv_dmaclr) \ @@ -158,13 +159,19 @@ struct ispmdvec { ISP_WRITE(isp, isp->isp_rqstinrp, nxti); \ isp->isp_reqidx = nxti +#define ISP_SYNC_REQUEST(isp) \ + MEMORYBARRIER(isp, SYNC_REQUEST, isp->isp_reqidx, QENTRY_LEN); \ + isp->isp_reqidx = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); \ + ISP_WRITE(isp, isp->isp_rqstinrp, isp->isp_reqidx) + /* * SCSI Specific Host Adapter Parameters- per bus, per target */ typedef struct { - uint32_t : 10, - isp_bad_nvram : 1, - isp_gotdparms : 1, + uint32_t : 8, + update : 1, + sendmarker : 1, + role : 2, isp_req_ack_active_neg : 1, isp_data_line_active_neg: 1, isp_cmd_dma_burst_enable: 1, @@ -184,7 +191,7 @@ typedef struct { uint8_t isp_retry_count; uint8_t isp_retry_delay; struct { - uint32_t + uint32_t exc_throttle : 8, : 1, dev_enable : 1, /* ignored */ @@ -237,11 +244,16 @@ typedef struct { #define SNS_ID 0x80 /* SNS Server Special ID */ #define NPH_MAX 0xfe +/* Use this handle for the base for multi-id firmware SNS logins */ +#define NPH_SNS_HDLBASE 0x400 + /* These are for 2K Login Firmware cards */ #define NPH_RESERVED 0x7F0 /* begin of reserved N-port handles */ #define NPH_MGT_ID 0x7FA /* Management Server Special ID */ #define NPH_SNS_ID 0x7FC /* SNS Server Special ID */ -#define NPH_FL_ID 0x7FE /* FL Port Special ID */ +#define NPH_FABRIC_CTLR 0x7FD /* Fabric Controller (0xFFFFFD) */ +#define NPH_FL_ID 0x7FE /* F Port Special ID (0xFFFFFE) */ +#define NPH_IP_BCST 0x7ff /* IP Broadcast Special ID (0xFFFFFF) */ #define NPH_MAX_2K 0x800 /* @@ -254,12 +266,27 @@ typedef struct { */ #define LOCAL_LOOP_LIM 126 +/* + * Limit for (2K login) N-port handle amounts + */ +#define MAX_NPORT_HANDLE 2048 + +/* + * Special Constants + */ +#define INI_NONE ((uint64_t) 0) +#define ISP_NOCHAN 0xff + /* * Special Port IDs */ #define MANAGEMENT_PORT_ID 0xFFFFFA #define SNS_PORT_ID 0xFFFFFC #define FABRIC_PORT_ID 0xFFFFFE +#define PORT_ANY 0xFFFFFF +#define PORT_NONE 0 +#define DOMAIN_CONTROLLER_BASE 0xFFFC00 +#define DOMAIN_CONTROLLER_END 0xFFFCFF /* @@ -271,11 +298,11 @@ typedef struct { * * It has a state. If the state if VALID, that means that we've logged into * the device. We also *may* have a initiator map index entry. This is a value - * from 0..MAX_FC_TARG that is used to index into the isp_ini_map array. If + * from 0..MAX_FC_TARG that is used to index into the isp_dev_map array. If * the value therein is non-zero, then that value minus one is used to index * into the Port Database to find the handle for forming commands. There is - * back-index minus one value within to Port Database entry that tells us - * which entry in isp_ini_map points to us (to avoid searching). + * back-index minus one value within to Port Database entry that tells us + * which entry in isp_dev_map points to us (to avoid searching). * * Local loop devices the firmware automatically performs PLOGI on for us * (which is why that handle is imposed upon us). Fabric devices we assign @@ -308,7 +335,7 @@ typedef struct { * * + There can never be two non-NIL entries with the same handle. * - * + There can never be two non-NIL entries which have the same ini_map_idx + * + There can never be two non-NIL entries which have the same dev_map_idx * value. */ typedef struct { @@ -318,27 +345,36 @@ typedef struct { * the 'loopid'. */ uint16_t handle; + /* - * The ini_map_idx, if nonzero, is the system virtual target ID (+1) - * as a cross-reference with the isp_ini_map. + * The dev_map_idx, if nonzero, is the system virtual target ID (+1) + * as a cross-reference with the isp_dev_map. * * A device is 'autologin' if the firmware automatically logs into * it (re-logins as needed). Basically, local private loop devices. * - * The state is the current state of thsi entry. + * The state is the current state of this entry. * * Role is Initiator, Target, Both * - * Portid is obvious, as or node && port WWNs. The new_role and + * Portid is obvious, as are node && port WWNs. The new_role and * new_portid is for when we are pending a change. + * + * The 'target_mode' tag means that this entry arrived via a + * target mode command and is immune from normal flushing rules. + * You should also never see anything with an initiator role + * with this set. */ - uint16_t ini_map_idx : 12, + uint16_t dev_map_idx : 12, autologin : 1, /* F/W does PLOGI/PLOGO */ state : 3; - uint32_t reserved : 6, + uint32_t reserved : 5, + target_mode : 1, roles : 2, portid : 24; - uint32_t new_reserved : 6, + uint32_t + dirty : 1, /* commands have been run */ + new_reserved : 5, new_roles : 2, new_portid : 24; uint64_t node_wwn; @@ -356,34 +392,47 @@ typedef struct { /* * FC card specific information + * + * This structure is replicated across multiple channels for multi-id + * capapble chipsets, with some entities different on a per-channel basis. */ + typedef struct { - uint32_t : 10, - isp_tmode : 1, - isp_2klogin : 1, - isp_sccfw : 1, - isp_gbspeed : 3, - : 1, - : 1, - isp_gotdparms : 1, - isp_bad_nvram : 1, + uint32_t + link_active : 1, + npiv_fabric : 1, + inorder : 1, + sendmarker : 1, + role : 2, + isp_gbspeed : 4, isp_loopstate : 4, /* Current Loop State */ isp_fwstate : 4, /* ISP F/W state */ - isp_topo : 3, + isp_topo : 3, /* Connection Type */ loop_seen_once : 1; + uint32_t : 8, isp_portid : 24; /* S_ID */ + + uint16_t isp_fwoptions; uint16_t isp_xfwoptions; uint16_t isp_zfwoptions; - uint16_t isp_loopid; /* hard loop id */ - uint16_t isp_fwattr; /* firmware attributes */ - uint16_t isp_execthrottle; + uint16_t isp_loopid; /* hard loop id */ + uint16_t isp_sns_hdl; /* N-port handle for SNS */ + uint16_t isp_lasthdl; /* only valid for channel 0 */ + uint16_t isp_maxalloc; uint8_t isp_retry_delay; uint8_t isp_retry_count; - uint8_t isp_reserved; - uint16_t isp_maxalloc; - uint16_t isp_maxfrmlen; + + /* + * Current active WWNN/WWPN + */ + uint64_t isp_wwnn; + uint64_t isp_wwpn; + + /* + * NVRAM WWNN/WWPN + */ uint64_t isp_wwnn_nvram; uint64_t isp_wwpn_nvram; @@ -399,16 +448,25 @@ typedef struct { * subtract one to get the portdb index. This means that * entries which are zero are unmapped (i.e., don't exist). */ - uint16_t isp_ini_map[MAX_FC_TARG]; + uint16_t isp_dev_map[MAX_FC_TARG]; + +#ifdef ISP_TARGET_MODE + /* + * This maps N-Port Handle to portdb entry so we + * don't have to search for every incoming command. + * + * The mapping function is to take any non-zero entry and + * subtract one to get the portdb index. This means that + * entries which are zero are unmapped (i.e., don't exist). + */ + uint16_t isp_tgt_map[MAX_NPORT_HANDLE]; +#endif /* * Scratch DMA mapped in area to fetch Port Database stuff, etc. */ void * isp_scratch; XS_DMA_ADDR_T isp_scdma; -#ifdef ISP_FW_CRASH_DUMP - uint16_t * isp_dump_data; -#endif } fcparam; #define FW_CONFIG_WAIT 0 @@ -457,7 +515,6 @@ struct ispsoftc { void * isp_param; /* type specific */ uint16_t isp_fwrev[3]; /* Loaded F/W revision */ - uint16_t isp_romfw_rev[3]; /* PROM F/W revision */ uint16_t isp_maxcmds; /* max possible I/O cmds */ uint8_t isp_type; /* HBA Chip Type */ uint8_t isp_revision; /* HBA Chip H/W Revision */ @@ -466,22 +523,20 @@ struct ispsoftc { uint32_t isp_clock : 8, /* input clock */ : 4, isp_port : 1, /* 23XX/24XX only */ - isp_failed : 1, /* board failed */ isp_open : 1, /* opened (ioctl) */ - isp_touched : 1, /* board ever seen? */ isp_bustype : 1, /* SBus or PCI */ isp_loaded_fw : 1, /* loaded firmware */ - isp_role : 2, /* roles supported */ - isp_dblev : 12; /* debug log mask */ + isp_dblev : 16; /* debug log mask */ - uint32_t isp_confopts; /* config options */ + uint16_t isp_fwattr; /* firmware attributes */ + uint16_t isp_nchan; /* number of channels */ + + uint32_t isp_confopts; /* config options */ uint32_t isp_rqstinrp; /* register for REQINP */ uint32_t isp_rqstoutrp; /* register for REQOUTP */ uint32_t isp_respinrp; /* register for RESINP */ uint32_t isp_respoutrp; /* register for RESOUTP */ - uint32_t isp_atioinrp; /* register for ATIOINP */ - uint32_t isp_atiooutrp; /* register for ATIOOUTP */ /* * Instrumentation @@ -494,24 +549,26 @@ struct ispsoftc { uint64_t isp_fphccmplt; /* CMDs via fastpost */ uint16_t isp_rscchiwater; uint16_t isp_fpcchiwater; + NANOTIME_T isp_init_time; /* time were last initialized */ /* * Volatile state */ volatile uint32_t : 8, + : 2, + isp_dead : 1, + : 1, isp_mboxbsy : 1, /* mailbox command active */ isp_state : 3, - isp_sendmarker : 2, /* send a marker entry */ - isp_update : 2, /* update parameters */ isp_nactive : 16; /* how many commands active */ volatile uint32_t isp_reqodx; /* index of last ISP pickup */ volatile uint32_t isp_reqidx; /* index of next request */ volatile uint32_t isp_residx; /* index of next result */ volatile uint32_t isp_resodx; /* index of next result */ - volatile uint32_t isp_rspbsy; volatile uint32_t isp_lasthdls; /* last handle seed */ volatile uint32_t isp_obits; /* mailbox command output */ + volatile uint32_t isp_serno; /* rolling serial number */ volatile uint16_t isp_mboxtmp[MAILBOX_STORAGE]; volatile uint16_t isp_lastmbxcmd; /* last mbox command sent */ volatile uint16_t isp_mbxwrk0; @@ -527,7 +584,7 @@ struct ispsoftc { #ifdef ISP_TARGET_MODE /* - * Active target commands are stored here, indexed by handle function. + * Active target commands are stored here, indexed by handle functions. */ void **isp_tgtlist; #endif @@ -546,8 +603,20 @@ struct ispsoftc { #endif }; -#define SDPARAM(isp) ((sdparam *) (isp)->isp_param) -#define FCPARAM(isp) ((fcparam *) (isp)->isp_param) +#define SDPARAM(isp, chan) (&((sdparam *)(isp)->isp_param)[(chan)]) +#define FCPARAM(isp, chan) (&((fcparam *)(isp)->isp_param)[(chan)]) + +#define ISP_SET_SENDMARKER(isp, chan, val) \ + if (IS_FC(isp)) { \ + FCPARAM(isp, chan)->sendmarker = val; \ + } else { \ + SDPARAM(isp, chan)->sendmarker = val; \ + } + +#define ISP_TST_SENDMARKER(isp, chan) \ + (IS_FC(isp)? \ + FCPARAM(isp, chan)->sendmarker != 0 : \ + SDPARAM(isp, chan)->sendmarker != 0) /* * ISP Driver Run States @@ -571,23 +640,22 @@ struct ispsoftc { #define ISP_CFG_NPORT 0x04 /* prefer {N/F}-Port connection */ #define ISP_CFG_NPORT_ONLY 0x08 /* insist on {N/F}-Port connection */ #define ISP_CFG_LPORT_ONLY 0x0C /* insist on {N/F}L-Port connection */ -#define ISP_CFG_OWNWWPN 0x100 /* override NVRAM wwpn */ -#define ISP_CFG_OWNWWNN 0x200 /* override NVRAM wwnn */ #define ISP_CFG_OWNFSZ 0x400 /* override NVRAM frame size */ #define ISP_CFG_OWNLOOPID 0x800 /* override NVRAM loopid */ #define ISP_CFG_OWNEXCTHROTTLE 0x1000 /* override NVRAM execution throttle */ #define ISP_CFG_FOURGB 0x2000 /* force 4GB connection (24XX only) */ /* - * Prior to calling isp_reset for the first time, the outer layer - * should set isp_role to one of NONE, INITIATOR, TARGET, BOTH. + * For each channel, the outer layers should know what role that channel + * will take: ISP_ROLE_NONE, ISP_ROLE_INITIATOR, ISP_ROLE_TARGET, + * ISP_ROLE_BOTH. * * If you set ISP_ROLE_NONE, the cards will be reset, new firmware loaded, * NVRAM read, and defaults set, but any further initialization (e.g. * INITIALIZE CONTROL BLOCK commands for 2X00 cards) won't be done. * * If INITIATOR MODE isn't set, attempts to run commands will be stopped - * at isp_start and completed with the moral equivalent of SELECTION TIMEOUT. + * at isp_start and completed with the equivalent of SELECTION TIMEOUT. * * If TARGET MODE is set, it doesn't mean that the rest of target mode support * needs to be enabled, or will even work. What happens with the 2X00 cards @@ -665,8 +733,10 @@ struct ispsoftc { #define ISP_HA_FC_2312 0x40 #define ISP_HA_FC_2322 0x50 #define ISP_HA_FC_2400 0x60 +#define ISP_HA_FC_2500 0x70 #define IS_SCSI(isp) (isp->isp_type & ISP_HA_SCSI) +#define IS_1020(isp) (isp->isp_type < ISP_HA_SCSI_1240) #define IS_1240(isp) (isp->isp_type == ISP_HA_SCSI_1240) #define IS_1080(isp) (isp->isp_type == ISP_HA_SCSI_1080) #define IS_1280(isp) (isp->isp_type == ISP_HA_SCSI_1280) @@ -688,6 +758,7 @@ struct ispsoftc { #define IS_2312(isp) ((isp)->isp_type == ISP_HA_FC_2312) #define IS_2322(isp) ((isp)->isp_type == ISP_HA_FC_2322) #define IS_24XX(isp) ((isp)->isp_type >= ISP_HA_FC_2400) +#define IS_25XX(isp) ((isp)->isp_type >= ISP_HA_FC_2500) /* * DMA related macros @@ -705,10 +776,9 @@ struct ispsoftc { */ /* - * Reset Hardware. Totally. Assumes that you'll follow this with - * a call to isp_init. + * Reset Hardware. Totally. Assumes that you'll follow this with a call to isp_init. */ -void isp_reset(ispsoftc_t *); +void isp_reset(ispsoftc_t *, int); /* * Initialize Hardware to known state @@ -718,14 +788,7 @@ void isp_init(ispsoftc_t *); /* * Reset the ISP and call completion for any orphaned commands. */ -void isp_reinit(ispsoftc_t *); - -#ifdef ISP_FW_CRASH_DUMP -/* - * Dump firmware entry point. - */ -void isp_fw_dump(ispsoftc_t *isp); -#endif +void isp_reinit(ispsoftc_t *, int); /* * Internal Interrupt Service Routine @@ -757,27 +820,34 @@ void isp_done(XS_T *); * Platform Dependent to External to Internal Control Function * * Assumes locks are held on entry. You should note that with many of - * these commands and locks may be released while this is occurring. + * these commands locks may be released while this function is called. * - * A few notes about some of these functions: - * - * ISPCTL_FCLINK_TEST tests to make sure we have good fibre channel link. - * The argument is a pointer to an integer which is the time, in microseconds, - * we should wait to see whether we have good link. This test, if successful, - * lets us know our connection topology and our Loop ID/AL_PA and so on. - * You can't get anywhere without this. - * - * ISPCTL_SCAN_FABRIC queries the name server (if we're on a fabric) for - * all entities using the FC Generic Services subcommand GET ALL NEXT. - * For each found entity, an ISPASYNC_FABRICDEV event is generated (see - * below). - * - * ISPCTL_SCAN_LOOP does a local loop scan. This is only done if the connection - * topology is NL or FL port (private or public loop). Since the Qlogic f/w - * 'automatically' manages local loop connections, this function essentially - * notes the arrival, departure, and possible shuffling around of local loop - * entities. Thus for each arrival and departure this generates an isp_async - * event of ISPASYNC_PROMENADE (see below). + * ... ISPCTL_RESET_BUS, int channel); + * Reset BUS on this channel + * ... ISPCTL_RESET_DEV, int channel, int target); + * Reset Device on this channel at this target. + * ... ISPCTL_ABORT_CMD, XS_T *xs); + * Abort active transaction described by xs. + * ... IPCTL_UPDATE_PARAMS); + * Update any operating parameters (speed, etc.) + * ... ISPCTL_FCLINK_TEST, int channel); + * Test FC link status on this channel + * ... ISPCTL_SCAN_FABRIC, int channel); + * Scan fabric on this channel + * ... ISPCTL_SCAN_LOOP, int channel); + * Scan local loop on this channel + * ... ISPCTL_PDB_SYNC, int channel); + * Synchronize port database on this channel + * ... ISPCTL_SEND_LIP, int channel); + * Send a LIP on this channel + * ... ISPCTL_GET_NAMES, int channel, int np, uint64_t *wwnn, uint64_t *wwpn) + * Get a WWNN/WWPN for this N-port handle on this channel + * ... ISPCTL_RUN_MBOXCMD, mbreg_t *mbp) + * Run this mailbox command + * ... ISPCTL_GET_PDB, int channel, int nphandle, isp_pdb_t *pdb) + * Get PDB on this channel for this N-port handle + * ... ISPCTL_PLOGX, isp_plcmd_t *) + * Performa a port login/logout * * ISPCTL_PDB_SYNC is somewhat misnamed. It actually is the final step, in * order, of ISPCTL_FCLINK_TEST, ISPCTL_SCAN_FABRIC, and ISPCTL_SCAN_LOOP. @@ -788,89 +858,48 @@ void isp_done(XS_T *); * part of this function. It's now been separated to allow for finer control. */ typedef enum { - ISPCTL_RESET_BUS, /* Reset Bus */ - ISPCTL_RESET_DEV, /* Reset Device */ - ISPCTL_ABORT_CMD, /* Abort Command */ - ISPCTL_UPDATE_PARAMS, /* Update Operating Parameters (SCSI) */ - ISPCTL_FCLINK_TEST, /* Test FC Link Status */ - ISPCTL_SCAN_FABRIC, /* (Re)scan Fabric Name Server */ - ISPCTL_SCAN_LOOP, /* (Re)scan Local Loop */ - ISPCTL_PDB_SYNC, /* Synchronize Port Database */ - ISPCTL_SEND_LIP, /* Send a LIP */ - ISPCTL_GET_PORTNAME, /* get portname from an N-port handle */ - ISPCTL_RUN_MBOXCMD, /* run a mailbox command */ - ISPCTL_TOGGLE_TMODE, /* toggle target mode */ - ISPCTL_GET_PDB, /* get a single port database entry */ - ISPCTL_PLOGX /* do a port login/logout */ + ISPCTL_RESET_BUS, + ISPCTL_RESET_DEV, + ISPCTL_ABORT_CMD, + ISPCTL_UPDATE_PARAMS, + ISPCTL_FCLINK_TEST, + ISPCTL_SCAN_FABRIC, + ISPCTL_SCAN_LOOP, + ISPCTL_PDB_SYNC, + ISPCTL_SEND_LIP, + ISPCTL_GET_NAMES, + ISPCTL_RUN_MBOXCMD, + ISPCTL_GET_PDB, + ISPCTL_PLOGX } ispctl_t; -int isp_control(ispsoftc_t *, ispctl_t, void *); - +int isp_control(ispsoftc_t *, ispctl_t, ...); /* * Platform Dependent to Internal to External Control Function - * (each platform must provide such a function) - * - * Assumes locks are held. - * - * A few notes about some of these functions: - * - * ISPASYNC_CHANGE_NOTIFY notifies the outer layer that a change has - * occurred that invalidates the list of fabric devices known and/or - * the list of known loop devices. The argument passed is a pointer - * whose values are defined below (local loop change, name server - * change, other). 'Other' may simply be a LIP, or a change in - * connection topology. - * - * ISPASYNC_FABRIC_DEV announces the next element in a list of - * fabric device names we're getting out of the name server. The - * argument points to a GET ALL NEXT response structure. The list - * is known to terminate with an entry that refers to ourselves. - * One of the main purposes of this function is to allow outer - * layers, which are OS dependent, to set policy as to which fabric - * devices might actually be logged into (and made visible) later - * at ISPCTL_PDB_SYNC time. Since there's a finite number of fabric - * devices that we can log into (256 less 3 'reserved' for F-port - * topologies), and fabrics can grow up to 8 million or so entries - * (24 bits of Port Address, less a wad of reserved spaces), clearly - * we had better let the OS determine login policy. - * - * ISPASYNC_PROMENADE has an argument that is a pointer to an integer which - * is an index into the portdb in the softc ('target'). Whether that entry's - * valid tag is set or not says whether something has arrived or departed. - * The name refers to a favorite pastime of many city dwellers- watching - * people come and go, talking of Michaelangelo, and so on.. - * - * ISPASYNC_UNHANDLED_RESPONSE gives outer layers a chance to parse a - * response queue entry not otherwise handled. The outer layer should - * return non-zero if it handled it. The 'arg' points to an unmassaged - * response queue entry. */ typedef enum { - ISPASYNC_NEW_TGT_PARAMS, /* New Target Parameters Negotiated */ - ISPASYNC_BUS_RESET, /* Bus Was Reset */ + ISPASYNC_NEW_TGT_PARAMS, /* SPI New Target Parameters */ + ISPASYNC_BUS_RESET, /* All Bus Was Reset */ ISPASYNC_LOOP_DOWN, /* FC Loop Down */ ISPASYNC_LOOP_UP, /* FC Loop Up */ - ISPASYNC_LIP, /* LIP Received */ - ISPASYNC_LOOP_RESET, /* Loop Reset Received */ + ISPASYNC_LIP, /* FC LIP Received */ + ISPASYNC_LOOP_RESET, /* FC Loop Reset Received */ ISPASYNC_CHANGE_NOTIFY, /* FC Change Notification */ - ISPASYNC_DEV_ARRIVED, /* FC Device Arrival */ - ISPASYNC_DEV_CHANGED, /* FC Device Change */ - ISPASYNC_DEV_STAYED, /* FC Device Stayed the Same */ - ISPASYNC_DEV_GONE, /* FC Device Depart */ - ISPASYNC_TARGET_NOTIFY, /* target asynchronous notification event */ - ISPASYNC_TARGET_ACTION, /* target action requested */ - ISPASYNC_CONF_CHANGE, /* Platform Configuration Change */ - ISPASYNC_UNHANDLED_RESPONSE, /* Unhandled Response Entry */ - ISPASYNC_FW_CRASH, /* Firmware has crashed */ - ISPASYNC_FW_DUMPED, /* Firmware crashdump taken */ - ISPASYNC_FW_RESTARTED /* Firmware has been restarted */ + ISPASYNC_DEV_ARRIVED, /* FC Device Arrived */ + ISPASYNC_DEV_CHANGED, /* FC Device Changed */ + ISPASYNC_DEV_STAYED, /* FC Device Stayed */ + ISPASYNC_DEV_GONE, /* FC Device Departure */ + ISPASYNC_TARGET_NOTIFY, /* All target async notification */ + ISPASYNC_TARGET_ACTION, /* All target action requested */ + ISPASYNC_FW_CRASH, /* All Firmware has crashed */ + ISPASYNC_FW_RESTARTED /* All Firmware has been restarted */ } ispasync_t; -int isp_async(ispsoftc_t *, ispasync_t, void *); +void isp_async(ispsoftc_t *, ispasync_t, ...); -#define ISPASYNC_CHANGE_PDB ((void *) 0) -#define ISPASYNC_CHANGE_SNS ((void *) 1) -#define ISPASYNC_CHANGE_OTHER ((void *) 2) +#define ISPASYNC_CHANGE_PDB 0 +#define ISPASYNC_CHANGE_SNS 1 +#define ISPASYNC_CHANGE_OTHER 2 /* * Platform Dependent Error and Debug Printout @@ -893,9 +922,10 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); #define ISP_LOGDEBUG2 0x40 /* log most debug messages */ #define ISP_LOGDEBUG3 0x80 /* log high frequency debug messages */ #define ISP_LOGSANCFG 0x100 /* log SAN configuration */ -#define ISP_LOGTDEBUG0 0x200 /* log simple debug messages (target mode) */ -#define ISP_LOGTDEBUG1 0x400 /* log intermediate debug messages (target) */ -#define ISP_LOGTDEBUG2 0x800 /* log all debug messages (target) */ +#define ISP_LOGTINFO 0x1000 /* log informational messages (target mode) */ +#define ISP_LOGTDEBUG0 0x2000 /* log simple debug messages (target mode) */ +#define ISP_LOGTDEBUG1 0x4000 /* log intermediate debug messages (target) */ +#define ISP_LOGTDEBUG2 0x8000 /* log all debug messages (target) */ /* * Each Platform provides it's own isposinfo substructure of the ispsoftc @@ -904,13 +934,16 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); * Each platform must also provide the following macros/defines: * * - * ISP2100_SCRLEN - length for the Fibre Channel scratch DMA area + * ISP_FC_SCRLEN FC scratch area DMA length * - * MEMZERO(dst, src) platform zeroing function - * MEMCPY(dst, src, count) platform copying function - * SNPRINTF(buf, bufsize, fmt, ...) snprintf - * USEC_DELAY(usecs) microsecond spindelay function - * USEC_SLEEP(isp, usecs) microsecond sleep function + * ISP_MEMZERO(dst, src) platform zeroing function + * ISP_MEMCPY(dst, src, count) platform copying function + * ISP_SNPRINTF(buf, bufsize, fmt, ...) snprintf + * ISP_DELAY(usecs) microsecond spindelay function + * ISP_SLEEP(isp, usecs) microsecond sleep function + * + * ISP_INLINE ___inline or not- depending on how + * good your debugger is * * NANOTIME_T nanosecond time type * @@ -921,8 +954,7 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); * NANOTIME_SUB(NANOTIME_T *, NANOTIME_T *) * subtract two NANOTIME_T values * - * - * MAXISPREQUEST(ispsoftc_t *) maximum request queue size + * MAXISPREQUEST(ispsoftc_t *) maximum request queue size * for this particular board type * * MEMORYBARRIER(ispsoftc_t *, barrier_type, offset, size) @@ -936,32 +968,36 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); * MBOX_NOTIFY_COMPLETE(ispsoftc_t *) notification of mbox cmd donee * MBOX_RELEASE(ispsoftc_t *) release lock on mailbox regs * - * FC_SCRATCH_ACQUIRE(ispsoftc_t *) acquire lock on FC scratch area - * FC_SCRATCH_RELEASE(ispsoftc_t *) acquire lock on FC scratch area + * FC_SCRATCH_ACQUIRE(ispsoftc_t *, chan) acquire lock on FC scratch area + * return -1 if you cannot + * FC_SCRATCH_RELEASE(ispsoftc_t *, chan) acquire lock on FC scratch area * * SCSI_GOOD SCSI 'Good' Status * SCSI_CHECK SCSI 'Check Condition' Status * SCSI_BUSY SCSI 'Busy' Status * SCSI_QFULL SCSI 'Queue Full' Status * - * XS_T Platform SCSI transaction type (i.e., command for HBA) - * XS_DMA_ADDR_T Platform PCI DMA Address Type - * XS_ISP(xs) gets an instance out of an XS_T - * XS_CHANNEL(xs) gets the channel (bus # for DUALBUS cards) "" - * XS_TGT(xs) gets the target "" - * XS_LUN(xs) gets the lun "" - * XS_CDBP(xs) gets a pointer to the scsi CDB "" - * XS_CDBLEN(xs) gets the CDB's length "" - * XS_XFRLEN(xs) gets the associated data transfer length "" - * XS_TIME(xs) gets the time (in milliseconds) for this command - * XS_RESID(xs) gets the current residual count - * XS_STSP(xs) gets a pointer to the SCSI status byte "" - * XS_SNSP(xs) gets a pointer to the associate sense data - * XS_SNSLEN(xs) gets the length of sense data storage - * XS_SNSKEY(xs) dereferences XS_SNSP to get the current stored Sense Key - * XS_TAG_P(xs) predicate of whether this command should be tagged - * XS_TAG_TYPE(xs) which type of tag to use - * XS_SETERR(xs) set error state + * XS_T Platform SCSI transaction type (i.e., command for HBA) + * XS_DMA_ADDR_T Platform PCI DMA Address Type + * XS_GET_DMA_SEG(..) Get 32 bit dma segment list value + * XS_GET_DMA64_SEG(..) Get 64 bit dma segment list value + * XS_ISP(xs) gets an instance out of an XS_T + * XS_CHANNEL(xs) gets the channel (bus # for DUALBUS cards) "" + * XS_TGT(xs) gets the target "" + * XS_LUN(xs) gets the lun "" + * XS_CDBP(xs) gets a pointer to the scsi CDB "" + * XS_CDBLEN(xs) gets the CDB's length "" + * XS_XFRLEN(xs) gets the associated data transfer length "" + * XS_TIME(xs) gets the time (in milliseconds) for this command + * XS_GET_RESID(xs) gets the current residual count + * XS_GET_RESID(xs, resid) sets the current residual count + * XS_STSP(xs) gets a pointer to the SCSI status byte "" + * XS_SNSP(xs) gets a pointer to the associate sense data + * XS_SNSLEN(xs) gets the length of sense data storage + * XS_SNSKEY(xs) dereferences XS_SNSP to get the current stored Sense Key + * XS_TAG_P(xs) predicate of whether this command should be tagged + * XS_TAG_TYPE(xs) which type of tag to use + * XS_SETERR(xs) set error state * * HBA_NOERROR command has no erros * HBA_BOTCH hba botched something @@ -979,32 +1015,31 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); * * XS_SAVE_SENSE(xs, sp, len) save sense data * - * XS_SET_STATE_STAT(isp, sp, xs) platform dependent interpreter of - * response queue entry status bits - * - * - * DEFAULT_IID(ispsoftc_t *) Default SCSI initiator ID - * DEFAULT_LOOPID(ispsoftc_t *) Default FC Loop ID - * DEFAULT_NODEWWN(ispsoftc_t *) Default Node WWN - * DEFAULT_PORTWWN(ispsoftc_t *) Default Port WWN * DEFAULT_FRAMESIZE(ispsoftc_t *) Default Frame Size - * DEFAULT_EXEC_THROTTLE(ispsoftc_t *) Default Execution Throttle + * DEFAULT_EXEC_THROTTLE(ispsoftc_t *) Default Execution Throttle + * + * GET_DEFAULT_ROLE(ispsoftc_t *, int) Get Default Role for a channel + * SET_DEFAULT_ROLE(ispsoftc_t *, int, int) Set Default Role for a channel + * DEFAULT_IID(ispsoftc_t *, int) Default SCSI initiator ID + * DEFAULT_LOOPID(ispsoftc_t *, int) Default FC Loop ID + * * These establish reasonable defaults for each platform. * These must be available independent of card NVRAM and are * to be used should NVRAM not be readable. * - * ISP_NODEWWN(ispsoftc_t *) FC Node WWN to use - * ISP_PORTWWN(ispsoftc_t *) FC Port WWN to use + * DEFAULT_NODEWWN(ispsoftc_t *, chan) Default FC Node WWN to use + * DEFAULT_PORTWWN(ispsoftc_t *, chan) Default FC Port WWN to use * - * These are to be used after NVRAM is read. The tags - * in fcparam.isp_ww{n,p}n_nvram reflect the values - * read from NVRAM (possibly corrected for card botches). - * Each platform can take that information and override - * it or ignore and return the Node and Port WWNs to be - * used when sending the Qlogic f/w the Initialization - * Control Block. + * These defines are hooks to allow the setting of node and + * port WWNs when NVRAM cannot be read or is to be overriden. + * + * ACTIVE_NODEWWN(ispsoftc_t *, chan) FC Node WWN to use + * ACTIVE_PORTWWN(ispsoftc_t *, chan) FC Port WWN to use + * + * After NVRAM is read, these will be invoked to get the + * node and port WWNs that will actually be used for this + * channel. * - * (XXX these do endian specific transformations- in transition XXX) * * ISP_IOXPUT_8(ispsoftc_t *, uint8_t srcval, uint8_t *dstptr) * ISP_IOXPUT_16(ispsoftc_t *, uint16_t srcval, uint16_t *dstptr) @@ -1020,4 +1055,61 @@ int isp_async(ispsoftc_t *, ispasync_t, void *); * ISP_SWAP32(ispsoftc_t *, uint32_t srcval) */ +#ifdef ISP_TARGET_MODE +/* + * The functions below are for the publicly available + * target mode functions that are internal to the Qlogic driver. + */ + +/* + * This function handles new response queue entry appropriate for target mode. + */ +int isp_target_notify(ispsoftc_t *, void *, uint32_t *); + +/* + * This function externalizes the ability to acknowledge an Immediate Notify request. + */ +int isp_notify_ack(ispsoftc_t *, void *); + +/* + * This function externalized acknowledging (success/fail) an ABTS frame + */ +int isp_acknak_abts(ispsoftc_t *, void *, int); + +/* + * Enable/Disable/Modify a logical unit. + * (softc, cmd, bus, tgt, lun, cmd_cnt, inotify_cnt) + */ +#define DFLT_CMND_CNT 0xfe /* unmonitored */ +#define DFLT_INOT_CNT 0xfe /* unmonitored */ +int isp_lun_cmd(ispsoftc_t *, int, int, int, int, int); + +/* + * General request queue 'put' routine for target mode entries. + */ +int isp_target_put_entry(ispsoftc_t *isp, void *); + +/* + * General routine to put back an ATIO entry- + * used for replenishing f/w resource counts. + * The argument is a pointer to a source ATIO + * or ATIO2. + */ +int isp_target_put_atio(ispsoftc_t *, void *); + +/* + * General routine to send a final CTIO for a command- used mostly for + * local responses. + */ +int isp_endcmd(ispsoftc_t *, ...); +#define ECMD_SVALID 0x100 +#define ECMD_TERMINATE 0x200 + +/* + * Handle an asynchronous event + * + * Return nonzero if the interrupt that generated this event has been dismissed. + */ +int isp_target_async(ispsoftc_t *, int, int); +#endif #endif /* _ISPVAR_H */