diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 21:27:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 21:27:18 -0700 |
commit | f7d57e42e7ebd085133506ef6325e70e822196dc (patch) | |
tree | 1851633f96b1eeaac58edcff94669bed3921dec7 | |
parent | 51bece910d2b0aca64cd3dee9fa2a8aa7feeadd9 (diff) | |
parent | c4e00fac42f268ed0a547cdd1d12bb8399864040 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (57 commits)
[SCSI] fix error handling in scsi_io_completion
[SCSI] qla1280: fix section mismatch warnings
[SCSI] mptsas: eliminate ghost devices
[SCSI] qla2xxx: make some more functions static
[SCSI] small whitespace cleanup for qlogic driver
[SCSI] mptbase: mpt_interrupt should return IRQ_NONE
[SCSI] mptsas: make two functions static
[SCSI] sg.c: Fix bad error handling in
[SCSI] 53c700: fix breakage caused by the autosense update
[SCSI] iscsi: add async notification of session events
[SCSI] iscsi: pass target nr to session creation
[SCSI] iscsi: break up session creation into two stages
[SCSI] iscsi: rm channel usage from iscsi
[SCSI] iscsi: fix session refcouting
[SCSI] iscsi: convert iscsi_tcp to new set/get param fns
[SCSI] iscsi: convert iser to new set/get param fns
[SCSI] iscsi: fixup set/get param functions
[SCSI] iscsi: add target discvery event to transport class
[SCSI] st: remove unused st_buffer.in_use
[SCSI] atp870u: reduce huge stack usage
...
74 files changed, 4502 insertions, 2864 deletions
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index 0a85a7e8120..d9e5960dafd 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,4 +1,20 @@ +1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com> +2 Current Version : 00.00.03.01 +3 Older Version : 00.00.02.04 + +i. Added support for ZCR controller. + + New device id 0x413 added. + +ii. Bug fix : Disable controller interrupt before firing INIT cmd to FW. + + Interrupt is enabled after required initialization is over. + This is done to ensure that driver is ready to handle interrupts when + it is generated by the controller. + + -Sumant Patro <Sumant.Patro@lsil.com> + 1 Release Date : Wed Feb 03 14:31:44 PST 2006 - Sumant Patro <Sumant.Patro@lsil.com> 2 Current Version : 00.00.02.04 3 Older Version : 00.00.02.04 diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index b2c033edb03..34b0da5cfa0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -437,159 +437,50 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, } static int -iscsi_iser_conn_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t value) +iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) { - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - - spin_lock_bh(&session->lock); - if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && - conn->stop_stage != STOP_CONN_RECOVER) { - printk(KERN_ERR "iscsi_iser: can not change parameter [%d]\n", - param); - spin_unlock_bh(&session->lock); - return 0; - } - spin_unlock_bh(&session->lock); + int value; switch (param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: /* TBD */ break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - conn->max_xmit_dlength = value; - break; case ISCSI_PARAM_HDRDGST_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; case ISCSI_PARAM_DATADGST_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; - case ISCSI_PARAM_INITIAL_R2T_EN: - session->initial_r2t_en = value; - break; - case ISCSI_PARAM_IMM_DATA_EN: - session->imm_data_en = value; - break; - case ISCSI_PARAM_FIRST_BURST: - session->first_burst = value; - break; - case ISCSI_PARAM_MAX_BURST: - session->max_burst = value; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - session->pdu_inorder_en = value; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - session->dataseq_inorder_en = value; - break; - case ISCSI_PARAM_ERL: - session->erl = value; - break; case ISCSI_PARAM_IFMARKER_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "IFMarker wasn't negotiated to No"); return -EPROTO; } break; case ISCSI_PARAM_OFMARKER_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "OFMarker wasn't negotiated to No"); return -EPROTO; } break; default: - break; - } - - return 0; -} - -static int -iscsi_iser_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, uint32_t *value) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct iscsi_session *session = iscsi_hostdata(shost->hostdata); - - switch (param) { - case ISCSI_PARAM_INITIAL_R2T_EN: - *value = session->initial_r2t_en; - break; - case ISCSI_PARAM_MAX_R2T: - *value = session->max_r2t; - break; - case ISCSI_PARAM_IMM_DATA_EN: - *value = session->imm_data_en; - break; - case ISCSI_PARAM_FIRST_BURST: - *value = session->first_burst; - break; - case ISCSI_PARAM_MAX_BURST: - *value = session->max_burst; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - *value = session->pdu_inorder_en; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - *value = session->dataseq_inorder_en; - break; - case ISCSI_PARAM_ERL: - *value = session->erl; - break; - case ISCSI_PARAM_IFMARKER_EN: - *value = 0; - break; - case ISCSI_PARAM_OFMARKER_EN: - *value = 0; - break; - default: - return ISCSI_ERR_PARAM_NOT_FOUND; - } - - return 0; -} - -static int -iscsi_iser_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t *value) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = 0; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = 0; - break; - /*case ISCSI_PARAM_TARGET_RECV_DLENGTH: - *value = conn->target_recv_dlength; - break; - case ISCSI_PARAM_INITIATOR_RECV_DLENGTH: - *value = conn->initiator_recv_dlength; - break;*/ - default: - return ISCSI_ERR_PARAM_NOT_FOUND; + return iscsi_set_param(cls_conn, param, buf, buflen); } return 0; } - static void iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { @@ -701,7 +592,12 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_FIRST_BURST | ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN | - ISCSI_DATASEQ_INORDER_EN, + ISCSI_DATASEQ_INORDER_EN | + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .host_template = &iscsi_iser_sht, .conndata_size = sizeof(struct iscsi_conn), .max_lun = ISCSI_ISER_MAX_LUN, @@ -713,9 +609,9 @@ static struct iscsi_transport iscsi_iser_transport = { .create_conn = iscsi_iser_conn_create, .bind_conn = iscsi_iser_conn_bind, .destroy_conn = iscsi_iser_conn_destroy, - .set_param = iscsi_iser_conn_set_param, - .get_conn_param = iscsi_iser_conn_get_param, - .get_session_param = iscsi_iser_session_get_param, + .set_param = iscsi_iser_set_param, + .get_conn_param = iscsi_conn_get_param, + .get_session_param = iscsi_session_get_param, .start_conn = iscsi_iser_conn_start, .stop_conn = iscsi_conn_stop, /* these are called as part of conn recovery */ diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 51740b34622..b114236f439 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -33,6 +33,11 @@ # For mptfc: #CFLAGS_mptfc.o += -DMPT_DEBUG_FC +# For mptsas: +#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS +#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE + + #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o diff --git a/drivers/message/fusion/lsi/fc_log.h b/drivers/message/fusion/lsi/fc_log.h deleted file mode 100644 index dc98d46f907..00000000000 --- a/drivers/message/fusion/lsi/fc_log.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. - * - * NAME: fc_log.h - * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips - * DESCRIPTION: Contains the enumerated list of values that may be returned - * in the IOCLogInfo field of a MPI Default Reply Message. - * - * CREATION DATE: 6/02/2000 - * ID: $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $ - */ - - -/* - * MpiIocLogInfo_t enum - * - * These 32 bit values are used in the IOCLogInfo field of the MPI reply - * messages. - * The value is 0xabcccccc where - * a = The type of log info as per the MPI spec. Since these codes are - * all for Fibre Channel this value will always be 2. - * b = Specifies a subclass of the firmware where - * 0 = FCP Initiator - * 1 = FCP Target - * 2 = LAN - * 3 = MPI Message Layer - * 4 = FC Link - * 5 = Context Manager - * 6 = Invalid Field Offset - * 7 = State Change Info - * all others are reserved for future use - * c = A specific value within the subclass. - * - * NOTE: Any new values should be added to the end of each subclass so that the - * codes remain consistent across firmware releases. - */ -typedef enum _MpiIocLogInfoFc -{ - MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, - MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Bad Rx Frame, overrun */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ - MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN = 0x20000007, /* Scatter Gather overrun */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS = 0x20000008, /* Receiver detected context mismatch via invalid header */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type */ - MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE = 0x2000000A, /* Link failure occurred */ - MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT = 0x2000000B, /* Transmitter timeout error */ - - MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000, - MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */ - MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */ - MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ - MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ - MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound queue after a logout */ - MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ - - MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, - MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */ - MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */ - MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */ - MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */ - - MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000, - - MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000, - MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */ - MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */ - MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */ - MPI_IOCLOGINFO_FC_LINK_CRC_ERROR = 0x24000004, /* CRC check detected error on received frame */ - - MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000, - - MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */ - MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff, - - MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */ - -} MpiIocLogInfoFc_t; diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 02cdc840a06..81ad77622da 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -6,7 +6,7 @@ * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.10 + * mpi.h Version: 01.05.11 * * Version History * --------------- @@ -76,6 +76,7 @@ * Added EEDP IOCStatus codes. * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -106,7 +107,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0C) +#define MPI_HEADER_VERSION_UNIT (0x0D) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index b1becec27e1..47e13e360c1 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.11 + * mpi_cnfg.h Version: 01.05.12 * * Version History * --------------- @@ -266,6 +266,16 @@ * Added postpone SATA Init bit to SAS IO Unit Page 1 * ControlFlags. * Changed LogEntry format for Log Page 0. + * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4. + * Added Manufacturing Page 7. + * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING. + * Added IOC Page 6. + * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2. + * Added MaxLBAHigh field to RAID Volume Page 0. + * Added Nvdata version fields to SAS IO Unit Page 0. + * Added AdditionalControlFlags, MaxTargetPortConnectTime, + * ReportDeviceMissingDelay, and IODeviceMissingDelay + * fields to SAS IO Unit Page 1. * -------------------------------------------------------------------------- */ @@ -631,9 +641,11 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4 } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x03) +#define MPI_MANUFACTURING4_PAGEVERSION (0x04) /* defines for the Flags field */ +#define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80) +#define MPI_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x40) #define MPI_MANPAGE4_IME_DISABLE (0x20) #define MPI_MANPAGE4_IM_DISABLE (0x10) #define MPI_MANPAGE4_IS_DISABLE (0x08) @@ -668,6 +680,66 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_6 #define MPI_MANUFACTURING6_PAGEVERSION (0x00) +typedef struct _MPI_MANPAGE7_CONNECTOR_INFO +{ + U32 Pinout; /* 00h */ + U8 Connector[16]; /* 04h */ + U8 Location; /* 14h */ + U8 Reserved1; /* 15h */ + U16 Slot; /* 16h */ + U32 Reserved2; /* 18h */ +} MPI_MANPAGE7_CONNECTOR_INFO, MPI_POINTER PTR_MPI_MANPAGE7_CONNECTOR_INFO, + MpiManPage7ConnectorInfo_t, MPI_POINTER pMpiManPage7ConnectorInfo_t; + +/* defines for the Pinout field */ +#define MPI_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) + +/* defines for the Location field */ +#define MPI_MANPAGE7_LOCATION_UNKNOWN (0x01) +#define MPI_MANPAGE7_LOCATION_INTERNAL (0x02) +#define MPI_MANPAGE7_LOCATION_EXTERNAL (0x04) +#define MPI_MANPAGE7_LOCATION_SWITCHABLE (0x08) +#define MPI_MANPAGE7_LOCATION_AUTO (0x10) +#define MPI_MANPAGE7_LOCATION_NOT_PRESENT (0x20) +#define MPI_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumPhys at runtime. + */ +#ifndef MPI_MANPAGE7_CONNECTOR_INFO_MAX +#define MPI_MANPAGE7_CONNECTOR_INFO_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_MANUFACTURING_7 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 04h */ + U32 Reserved2; /* 08h */ + U32 Flags; /* 0Ch */ + U8 EnclosureName[16]; /* 10h */ + U8 NumPhys; /* 20h */ + U8 Reserved3; /* 21h */ + U16 Reserved4; /* 22h */ + MPI_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI_MANPAGE7_CONNECTOR_INFO_MAX]; /* 24h */ +} CONFIG_PAGE_MANUFACTURING_7, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_7, + ManufacturingPage7_t, MPI_POINTER pManufacturingPage7_t; + +#define MPI_MANUFACTURING7_PAGEVERSION (0x00) + +/* defines for the Flags field */ +#define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) + + /**************************************************************************** * IO Unit Config Pages ****************************************************************************/ @@ -867,7 +939,7 @@ typedef struct _CONFIG_PAGE_IOC_2 } CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, IOCPage2_t, MPI_POINTER pIOCPage2_t; -#define MPI_IOCPAGE2_PAGEVERSION (0x03) +#define MPI_IOCPAGE2_PAGEVERSION (0x04) /* IOC Page 2 Capabilities flags */ @@ -878,6 +950,7 @@ typedef struct _CONFIG_PAGE_IOC_2 #define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010) #define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020) #define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING (0x10000000) #define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000) #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000) #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000) @@ -975,6 +1048,44 @@ typedef struct _CONFIG_PAGE_IOC_5 #define MPI_IOCPAGE5_PAGEVERSION (0x00) +typedef struct _CONFIG_PAGE_IOC_6 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 CapabilitiesFlags; /* 04h */ + U8 MaxDrivesIS; /* 08h */ + U8 MaxDrivesIM; /* 09h */ + U8 MaxDrivesIME; /* 0Ah */ + U8 Reserved1; /* 0Bh */ + U8 MinDrivesIS; /* 0Ch */ + U8 MinDrivesIM; /* 0Dh */ + U8 MinDrivesIME; /* 0Eh */ + U8 Reserved2; /* 0Fh */ + U8 MaxGlobalHotSpares; /* 10h */ + U8 Reserved3; /* 11h */ + U16 Reserved4; /* 12h */ + U32 Reserved5; /* 14h */ + U32 SupportedStripeSizeMapIS; /* 18h */ + U32 SupportedStripeSizeMapIME; /* 1Ch */ + U32 Reserved6; /* 20h */ + U8 MetadataSize; /* 24h */ + U8 Reserved7; /* 25h */ + U16 Reserved8; /* 26h */ + U16 MaxBadBlockTableEntries; /* 28h */ + U16 Reserved9; /* 2Ah */ + U16 IRNvsramUsage; /* 2Ch */ + U16 Reserved10; /* 2Eh */ + U32 IRNvsramVersion; /* 30h */ + U32 Reserved11; /* 34h */ + U32 Reserved12; /* 38h */ +} CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6, + IOCPage6_t, MPI_POINTER pIOCPage6_t; + +#define MPI_IOCPAGE6_PAGEVERSION (0x00) + +/* IOC Page 6 Capabilities Flags */ + +#define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) + /**************************************************************************** * BIOS Config Pages @@ -1218,13 +1329,13 @@ typedef struct _CONFIG_PAGE_BIOS_2 U32 Reserved5; /* 14h */ U32 Reserved6; /* 18h */ U8 BootDeviceForm; /* 1Ch */ - U8 Reserved7; /* 1Dh */ + U8 PrevBootDeviceForm; /* 1Ch */ U16 Reserved8; /* 1Eh */ MPI_BIOSPAGE2_BOOT_DEVICE BootDevice; /* 20h */ } CONFIG_PAGE_BIOS_2, MPI_POINTER PTR_CONFIG_PAGE_BIOS_2, BIOSPage2_t, MPI_POINTER pBIOSPage2_t; -#define MPI_BIOSPAGE2_PAGEVERSION (0x01) +#define MPI_BIOSPAGE2_PAGEVERSION (0x02) #define MPI_BIOSPAGE2_FORM_MASK (0x0F) #define MPI_BIOSPAGE2_FORM_ADAPTER_ORDER (0x00) @@ -2080,7 +2191,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 RAID_VOL0_STATUS VolumeStatus; /* 08h */ RAID_VOL0_SETTINGS VolumeSettings; /* 0Ch */ U32 MaxLBA; /* 10h */ - U32 Reserved1; /* 14h */ + U32 MaxLBAHigh; /* 14h */ U32 StripeSize; /* 18h */ U32 Reserved2; /* 1Ch */ U32 Reserved3; /* 20h */ @@ -2092,7 +2203,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06) /* values for RAID Volume Page 0 InactiveStatus field */ #define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) @@ -2324,7 +2435,8 @@ typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 { CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ - U32 Reserved1; /* 08h */ + U16 NvdataVersionDefault; /* 08h */ + U16 NvdataVersionPersistent; /* 0Ah */ U8 NumPhys; /* 0Ch */ U8 Reserved2; /* 0Dh */ U16 Reserved3; /* 0Eh */ @@ -2332,7 +2444,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 } CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; -#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03) +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x04) /* values for SAS IO Unit Page 0 PortFlags */ #define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) @@ -2373,12 +2485,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA { - U8 Port; /* 00h */ - U8 PortFlags; /* 01h */ - U8 PhyFlags; /* 02h */ - U8 MaxMinLinkRate; /* 03h */ - U32 ControllerPhyDeviceInfo;/* 04h */ - U32 Reserved1; /* 08h */ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo; /* 04h */ + U16 MaxTargetPortConnectTime; /* 08h */ + U16 Reserved1; /* 0Ah */ } MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; @@ -2395,15 +2508,17 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ U16 ControlFlags; /* 08h */ U16 MaxNumSATATargets; /* 0Ah */ - U32 Reserved1; /* 0Ch */ + U16 AdditionalControlFlags; /* 0Ch */ + U16 Reserved1; /* 0Eh */ U8 NumPhys; /* 10h */ U8 SATAMaxQDepth; /* 11h */ - U16 Reserved2; /* 12h */ + U8 ReportDeviceMissingDelay; /* 12h */ + U8 IODeviceMissingDelay; /* 13h */ MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 14h */ } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; -#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x05) +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06) /* values for SAS IO Unit Page 1 ControlFlags */ #define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) @@ -2428,6 +2543,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 #define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) #define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) +/* values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ +#define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) +#define MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16 (0x80) + /* values for SAS IO Unit Page 1 PortFlags */ #define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) #define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 4a5f8dd1d76..582cfe7c2aa 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -6,25 +6,25 @@ Copyright (c) 2000-2005 LSI Logic Corporation. --------------------------------------- - Header Set Release Version: 01.05.12 - Header Set Release Date: 08-30-05 + Header Set Release Version: 01.05.13 + Header Set Release Date: 03-27-06 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.10 01.05.09 - mpi_ioc.h 01.05.10 01.05.09 - mpi_cnfg.h 01.05.11 01.05.10 - mpi_init.h 01.05.06 01.05.06 - mpi_targ.h 01.05.05 01.05.05 + mpi.h 01.05.11 01.05.10 + mpi_ioc.h 01.05.11 01.05.10 + mpi_cnfg.h 01.05.12 01.05.11 + mpi_init.h 01.05.07 01.05.06 + mpi_targ.h 01.05.06 01.05.05 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 mpi_raid.h 01.05.02 01.05.02 mpi_tool.h 01.05.03 01.05.03 mpi_inb.h 01.05.01 01.05.01 - mpi_sas.h 01.05.02 01.05.01 - mpi_type.h 01.05.02 01.05.01 - mpi_history.txt 01.05.12 01.05.11 + mpi_sas.h 01.05.03 01.05.02 + mpi_type.h 01.05.02 01.05.02 + mpi_history.txt 01.05.13 01.05.12 * Date Version Description @@ -93,6 +93,7 @@ mpi.h * Added EEDP IOCStatus codes. * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -170,6 +171,17 @@ mpi_ioc.h * Added new ReasonCode value for SAS Device Status Change * event. * Added new family code for FC949E. + * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR. + * Added additional Reason Codes and more event data fields + * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE. + * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and + * new event. + * Added MPI_EVENT_SAS_SMP_ERROR and event data structure. + * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event + * data structure. + * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event + * data structure. + * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -425,6 +437,16 @@ mpi_cnfg.h * Added postpone SATA Init bit to SAS IO Unit Page 1 * ControlFlags. * Changed LogEntry format for Log Page 0. + * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4. + * Added Manufacturing Page 7. + * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING. + * Added IOC Page 6. + * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2. + * Added MaxLBAHigh field to RAID Volume Page 0. + * Added Nvdata version fields to SAS IO Unit Page 0. + * Added AdditionalControlFlags, MaxTargetPortConnectTime, + * ReportDeviceMissingDelay, and IODeviceMissingDelay + * fields to SAS IO Unit Page 1. * -------------------------------------------------------------------------- mpi_init.h @@ -467,6 +489,7 @@ mpi_init.h * Added four new defines for SEP SlotStatus. * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. + * 03-27-06 01.05.07 Added Task Management type of Clear ACA. * -------------------------------------------------------------------------- mpi_targ.h @@ -511,6 +534,7 @@ mpi_targ.h * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. + * 03-27-06 01.05.06 Added a comment. * -------------------------------------------------------------------------- mpi_fc.h @@ -610,6 +634,10 @@ mpi_sas.h * 08-30-05 01.05.02 Added DeviceInfo bit for SEP. * Added PrimFlags and Primitive field to SAS IO Unit * Control request, and added a new operation code. + * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal, + * and Remove Device operations to SAS IO Unit Control. + * Added DevHandle field to SAS IO Unit Control request and + * reply. * -------------------------------------------------------------------------- mpi_type.h @@ -625,20 +653,20 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.12 01.05.11 01.05.10 01.05.09 ----------- -------- -------- -------- -------- -mpi.h 01.05.10 01.05.09 01.05.08 01.05.07 -mpi_ioc.h 01.05.10 01.05.09 01.05.09 01.05.08 -mpi_cnfg.h 01.05.11 01.05.10 01.05.09 01.05.08 -mpi_init.h 01.05.06 01.05.06 01.05.05 01.05.04 -mpi_targ.h 01.05.05 01.05.05 01.05.05 01.05.04 -mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 -mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 -mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_sas.h 01.05.02 01.05.01 01.05.01 01.05.01 -mpi_type.h 01.05.02 01.05.01 01.05.01 01.05.01 +Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 +---------- -------- -------- -------- -------- -------- +mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 +mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 +mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 +mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 +mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 +mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 +mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_sas.h 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01 +mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index 68941f459ca..c1c678989a2 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -6,7 +6,7 @@ * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * mpi_init.h Version: 01.05.06 + * mpi_init.h Version: 01.05.07 * * Version History * --------------- @@ -52,6 +52,7 @@ * Added four new defines for SEP SlotStatus. * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. + * 03-27-06 01.05.07 Added Task Management type of Clear ACA. * -------------------------------------------------------------------------- */ @@ -427,6 +428,7 @@ typedef struct _MSG_SCSI_TASK_MGMT #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) #define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) #define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index 2c5f43fa7c7..18ba407fd39 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.10 + * mpi_ioc.h Version: 01.05.11 * * Version History * --------------- @@ -87,6 +87,17 @@ * Added new ReasonCode value for SAS Device Status Change * event. * Added new family code for FC949E. + * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR. + * Added additional Reason Codes and more event data fields + * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE. + * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and + * new event. + * Added MPI_EVENT_SAS_SMP_ERROR and event data structure. + * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event + * data structure. + * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event + * data structure. + * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. * -------------------------------------------------------------------------- */ @@ -272,6 +283,7 @@ typedef struct _MSG_IOC_FACTS_REPLY #define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) #define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200) #define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400) +#define MPI_IOCFACTS_CAPABILITY_TLR (0x00000800) /***************************************************************************** @@ -448,30 +460,34 @@ typedef struct _MSG_EVENT_ACK_REPLY /* Event */ -#define MPI_EVENT_NONE (0x00000000) -#define MPI_EVENT_LOG_DATA (0x00000001) -#define MPI_EVENT_STATE_CHANGE (0x00000002) -#define MPI_EVENT_UNIT_ATTENTION (0x00000003) -#define MPI_EVENT_IOC_BUS_RESET (0x00000004) -#define MPI_EVENT_EXT_BUS_RESET (0x00000005) -#define MPI_EVENT_RESCAN (0x00000006) -#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) -#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) -#define MPI_EVENT_LOGOUT (0x00000009) -#define MPI_EVENT_EVENT_CHANGE (0x0000000A) -#define MPI_EVENT_INTEGRATED_RAID (0x0000000B) -#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) -#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) -#define MPI_EVENT_QUEUE_FULL (0x0000000E) -#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) -#define MPI_EVENT_SAS_SES (0x00000010) -#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) -#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012) -#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013) -#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014) -#define MPI_EVENT_IR2 (0x00000015) -#define MPI_EVENT_SAS_DISCOVERY (0x00000016) -#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) +#define MPI_EVENT_NONE (0x00000000) +#define MPI_EVENT_LOG_DATA (0x00000001) +#define MPI_EVENT_STATE_CHANGE (0x00000002) +#define MPI_EVENT_UNIT_ATTENTION (0x00000003) +#define MPI_EVENT_IOC_BUS_RESET (0x00000004) +#define MPI_EVENT_EXT_BUS_RESET (0x00000005) +#define MPI_EVENT_RESCAN (0x00000006) +#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) +#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) +#define MPI_EVENT_LOGOUT (0x00000009) +#define MPI_EVENT_EVENT_CHANGE (0x0000000A) +#define MPI_EVENT_INTEGRATED_RAID (0x0000000B) +#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) +#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) +#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012) +#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013) +#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014) +#define MPI_EVENT_IR2 (0x00000015) +#define MPI_EVENT_SAS_DISCOVERY (0x00000016) +#define MPI_EVENT_SAS_BROADCAST_PRIMITIVE (0x00000017) +#define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018) +#define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019) +#define MPI_EVENT_SAS_SMP_ERROR (0x0000001A) +#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) /* AckRequired field values */ @@ -558,18 +574,25 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE U8 PhyNum; /* 0Eh */ U8 Reserved1; /* 0Fh */ U64 SASAddress; /* 10h */ + U8 LUN[8]; /* 18h */ + U16 TaskTag; /* 20h */ + U16 Reserved2; /* 22h */ } EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, MpiEventDataSasDeviceStatusChange_t, MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; /* MPI SAS Device Status Change Event data ReasonCode values */ -#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) -#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) -#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) -#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) +#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) /* SCSI Event data for Queue Full event */ @@ -742,6 +765,27 @@ typedef struct _EVENT_DATA_SAS_SES } EVENT_DATA_SAS_SES, MPI_POINTER PTR_EVENT_DATA_SAS_SES, MpiEventDataSasSes_t, MPI_POINTER pMpiEventDataSasSes_t; +/* SAS Broadcast Primitive Event data */ + +typedef struct _EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 00h */ + U8 Port; /* 01h */ + U8 PortWidth; /* 02h */ + U8 Primitive; /* 04h */ +} EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MPI_POINTER PTR_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MpiEventDataSasBroadcastPrimitive_t, + MPI_POINTER pMpiEventDataSasBroadcastPrimitive_t; + +#define MPI_EVENT_PRIMITIVE_CHANGE (0x01) +#define MPI_EVENT_PRIMITIVE_EXPANDER (0x03) +#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04) +#define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05) +#define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06) +#define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) + /* SAS Phy Link Status Event data */ typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS @@ -804,6 +848,53 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR #define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800) #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) +/* SAS SMP Error Event data */ + +typedef struct _EVENT_DATA_SAS_SMP_ERROR +{ + U8 Status; /* 00h */ + U8 Port; /* 01h */ + U8 SMPFunctionResult; /* 02h */ + U8 Reserved1; /* 03h */ + U64 SASAddress; /* 04h */ +} EVENT_DATA_SAS_SMP_ERROR, MPI_POINTER PTR_EVENT_DATA_SAS_SMP_ERROR, + MpiEventDataSasSmpError_t, MPI_POINTER pMpiEventDataSasSmpError_t; + +/* defines for the Status field of the SAS SMP Error event */ +#define MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID (0x00) +#define MPI_EVENT_SAS_SMP_CRC_ERROR (0x01) +#define MPI_EVENT_SAS_SMP_TIMEOUT (0x02) +#define MPI_EVENT_SAS_SMP_NO_DESTINATION (0x03) +#define MPI_EVENT_SAS_SMP_BAD_DESTINATION (0x04) + +/* SAS Initiator Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 00h */ + U8 Port; /* 01h */ + U16 DevHandle; /* 02h */ + U64 SASAddress; /* 04h */ +} EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MpiEventDataSasInitDevStatusChange_t, + MPI_POINTER pMpiEventDataSasInitDevStatusChange_t; + +/* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ +#define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) + +/* SAS Initiator Device Table Overflow Event data */ + +typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U8 MaxInit; /* 00h */ + U8 CurrentInit; /* 01h */ + U16 Reserved1; /* 02h */ +} EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MpiEventDataSasInitTableOverflow_t, + MPI_POINTER pMpiEventDataSasInitTableOverflow_t; + /***************************************************************************** * @@ -1013,5 +1104,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) #define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI_EXT_IMAGE_TYPE_INITIALIZATION (0x05) #endif diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index a9c14ad132c..871ebc08b70 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -13,6 +13,8 @@ #ifndef IOPI_IOCLOGINFO_H_INCLUDED #define IOPI_IOCLOGINFO_H_INCLUDED +#define SAS_LOGINFO_NEXUS_LOSS 0x31170000 +#define SAS_LOGINFO_MASK 0xFFFF0000 /****************************************************************************/ /* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */ @@ -51,6 +53,9 @@ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ + +#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ + #define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) #define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ @@ -103,6 +108,7 @@ #define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) #define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) #define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) +#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ @@ -165,11 +171,81 @@ /****************************************************************************/ /* IR LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IR */ /****************************************************************************/ -#define IR_LOGINFO_CODE_UNUSED1 (0x00010000) -#define IR_LOGINFO_CODE_UNUSED2 (0x00020000) +#define IR_LOGINFO_RAID_ACTION_ERROR (0x00010000) +#define IR_LOGINFO_CODE_UNUSED2 (0x00020000) + +/* Amount of information passed down for Create Volume is too large */ +#define IR_LOGINFO_VOLUME_CREATE_INVALID_LENGTH (0x00010001) +/* Creation of duplicate volume attempted (Bus/Target ID checked) */ +#define IR_LOGINFO_VOLUME_CREATE_DUPLICATE (0x00010002) +/* Creation failed due to maximum number of supported volumes exceeded */ +#define IR_LOGINFO_VOLUME_CREATE_NO_SLOTS (0x00010003) +/* Creation failed due to DMA error in trying to read from host */ +#define IR_LOGINFO_VOLUME_CREATE_DMA_ERROR (0x00010004) +/* Creation failed due to invalid volume type passed down */ +#define IR_LOGINFO_VOLUME_CREATE_INVALID_VOLUME_TYPE (0x00010005) +/* Creation failed due to error reading MFG Page 4 */ +#define IR_LOGINFO_VOLUME_MFG_PAGE4_ERROR (0x00010006) +/* Creation failed when trying to create internal structures */ +#define IR_LOGINFO_VOLUME_INTERNAL_CONFIG_STRUCTURE_ERROR (0x00010007) + +/* Activation failed due to trying to activate an already active volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_AN_ACTIVE_VOLUME (0x00010010) +/* Activation failed due to trying to active unsupported volume type */ +#define IR_LOGINFO_VOLUME_ACTIVATING_INVALID_VOLUME_TYPE (0x00010011) +/* Activation failed due to trying to active too many volumes */ +#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_VOLUMES (0x00010012) +/* Activation failed due to Volume ID in use already */ +#define IR_LOGINFO_VOLUME_ACTIVATING_VOLUME_ID_IN_USE (0x00010013) +/* Activation failed call to activateVolume returned failure */ +#define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014) +/* Activation failed trying to import the volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015) + +/* Phys Disk failed, too many phys disks */ +#define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020) +/* Amount of information passed down for Create Pnysdisk is too large */ +#define IR_LOGINFO_PHYSDISK_CREATE_INVALID_LENGTH (0x00010021) +/* Creation failed due to DMA error in trying to read from host */ +#define IR_LOGINFO_PHYSDISK_CREATE_DMA_ERROR (0x00010022) +/* Creation failed due to invalid Bus TargetID passed down */ +#define IR_LOGINFO_PHYSDISK_CREATE_BUS_TID_INVALID (0x00010023) +/* Creation failed due to error in creating RAID Phys Disk Config Page */ +#define IR_LOGINFO_PHYSDISK_CREATE_CONFIG_PAGE_ERROR (0x00010024) + + +/* Compatibility Error : IR Disabled */ +#define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030) +/* Compatibility Error : Inquiry Comand failed */ +#define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031) +/* Compatibility Error : Device not direct access device */ +#define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032) +/* Compatibility Error : Removable device found */ +#define IR_LOGINFO_COMPAT_ERROR_REMOVABLE_FOUND (0x00010033) +/* Compatibility Error : Device SCSI Version not 2 or higher */ +#define IR_LOGINFO_COMPAT_ERROR_NEED_SCSI_2_OR_HIGHER (0x00010034) +/* Compatibility Error : SATA device, 48 BIT LBA not supported */ +#define IR_LOGINFO_COMPAT_ERROR_SATA_48BIT_LBA_NOT_SUPPORTED (0x00010035) +/* Compatibility Error : Device does not have 512 byte block sizes */ +#define IR_LOGINFO_COMPAT_ERROR_DEVICE_NOT_512_BYTE_BLOCK (0x00010036) +/* Compatibility Error : Volume Type check failed */ +#define IR_LOGINFO_COMPAT_ERROR_VOLUME_TYPE_CHECK_FAILED (0x00010037) +/* Compatibility Error : Volume Type is unsupported by FW */ +#define IR_LOGINFO_COMPAT_ERROR_UNSUPPORTED_VOLUME_TYPE (0x00010038) +/* Compatibility Error : Disk drive too small for use in volume */ +#define IR_LOGINFO_COMPAT_ERROR_DISK_TOO_SMALL (0x00010039) +/* Compatibility Error : Phys disk for Create Volume not found */ +#define IR_LOGINFO_COMPAT_ERROR_PHYS_DISK_NOT_FOUND (0x0001003A) +/* Compatibility Error : membership count error, too many or too few disks for volume type */ +#define IR_LOGINFO_COMPAT_ERROR_MEMBERSHIP_COUNT (0x0001003B) +/* Compatibility Error : Disk stripe sizes must be 64KB */ +#define IR_LOGINFO_COMPAT_ERROR_NON_64K_STRIPE_SIZE (0x0001003C) +/* Compatibility Error : IME size limited to < 2TB */ +#define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D) + /****************************************************************************/ -/* Defines for convienence */ +/* Defines for convenience */ /****************************************************************************/ #define IOC_LOGINFO_PREFIX_IOP ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IOP) #define IOC_LOGINFO_PREFIX_PL ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_PL) diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h index 70514867bdd..50b8f0a8f45 100644 --- a/drivers/message/fusion/lsi/mpi_sas.h +++ b/drivers/message/fusion/lsi/mpi_sas.h @@ -6,7 +6,7 @@ * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: August 19, 2004 * - * mpi_sas.h Version: 01.05.02 + * mpi_sas.h Version: 01.05.03 * * Version History * --------------- @@ -17,6 +17,10 @@ * 08-30-05 01.05.02 Added DeviceInfo bit for SEP. * Added PrimFlags and Primitive field to SAS IO Unit * Control request, and added a new operation code. + * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal, + * and Remove Device operations to SAS IO Unit Control. + * Added DevHandle field to SAS IO Unit Control request and + * reply. * -------------------------------------------------------------------------- */ @@ -209,7 +213,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST U8 Reserved1; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U16 Reserved2; /* 04h */ + U16 DevHandle; /* 04h */ U8 Reserved3; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ @@ -231,6 +235,9 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST #define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) #define MPI_SAS_OP_MAP_CURRENT (0x09) #define MPI_SAS_OP_SEND_PRIMITIVE (0x0A) +#define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) +#define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) +#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* values for the PrimFlags field */ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) @@ -245,7 +252,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY U8 Reserved1; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U16 Reserved2; /* 04h */ + U16 DevHandle; /* 04h */ U8 Reserved3; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h index 3f462859cee..20b66731577 100644 --- a/drivers/message/fusion/lsi/mpi_targ.h +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -6,7 +6,7 @@ * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * mpi_targ.h Version: 01.05.05 + * mpi_targ.h Version: 01.05.06 * * Version History * --------------- @@ -54,6 +54,7 @@ * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. + * 03-27-06 01.05.06 Added a comment. * -------------------------------------------------------------------------- */ @@ -351,7 +352,7 @@ typedef struct _MSG_TARGET_ASSIST_REQUEST #define TARGET_ASSIST_FLAGS_CONFIRMED (0x08) #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) - +/* Standard Target Mode Reply message */ typedef struct _MSG_TARGET_ERROR_REPLY { U16 Reserved; /* 00h */ diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 57543603d6c..43308df6462 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -368,20 +368,21 @@ static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) { MPT_ADAPTER *ioc = bus_id; - u32 pa; + u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + + if (pa == 0xFFFFFFFF) + return IRQ_NONE; /* * Drain the reply FIFO! */ - while (1) { - pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); - if (pa == 0xFFFFFFFF) - return IRQ_HANDLED; - else if (pa & MPI_ADDRESS_REPLY_A_BIT) + do { + if (pa & MPI_ADDRESS_REPLY_A_BIT) mpt_reply(ioc, pa); else mpt_turbo_reply(ioc, pa); - } + pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + } while (pa != 0xFFFFFFFF); return IRQ_HANDLED; } @@ -1219,31 +1220,25 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) port = psize = 0; for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (psize) + continue; /* Get I/O space! */ port = pci_resource_start(pdev, ii); psize = pci_resource_len(pdev,ii); } else { + if (msize) + continue; /* Get memmap */ mem_phys = pci_resource_start(pdev, ii); msize = pci_resource_len(pdev,ii); - break; } } ioc->mem_size = msize; - if (ii == DEVICE_COUNT_RESOURCE) { - printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); - kfree(ioc); - return -EINVAL; - } - - dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); - dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); - mem = NULL; /* Get logical ptr for PciMem0 space */ /*mem = ioremap(mem_phys, msize);*/ - mem = ioremap(mem_phys, 0x100); + mem = ioremap(mem_phys, msize); if (mem == NULL) { printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); kfree(ioc); @@ -1343,11 +1338,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->bus_type = SAS; ioc->errata_flag_1064 = 1; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) { - ioc->prod_name = "LSISAS1066"; - ioc->bus_type = SAS; - ioc->errata_flag_1064 = 1; - } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) { ioc->prod_name = "LSISAS1068"; ioc->bus_type = SAS; @@ -1357,14 +1347,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->prod_name = "LSISAS1064E"; ioc->bus_type = SAS; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) { - ioc->prod_name = "LSISAS1066E"; - ioc->bus_type = SAS; - } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) { ioc->prod_name = "LSISAS1068E"; ioc->bus_type = SAS; } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + ioc->prod_name = "LSISAS1078"; + ioc->bus_type = SAS; + } if (ioc->errata_flag_1064) pci_disable_io_access(pdev); @@ -3184,6 +3174,37 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) u32 diag1val = 0; #endif + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " + "address=%p\n", ioc->name, __FUNCTION__, + &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); + CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); + if (sleepFlag == CAN_SLEEP) + msleep(1); + else + mdelay(1); + + for (count = 0; count < 60; count ++) { + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; + + drsprintk((MYIOC_s_INFO_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", + ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { + return 0; + } + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) + msleep(1000); + else + mdelay(1000); + } + return -1; + } + /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 32ae4d66454..a5ce10b67d0 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -75,8 +75,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.03.10" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.10" +#define MPT_LINUX_VERSION_COMMON "3.04.00" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.00" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -307,7 +307,8 @@ typedef struct _SYSIF_REGS u32 HostIndex; /* 50 Host Index register */ u32 Reserved4[15]; /* 54-8F */ u32 Fubar; /* 90 For Fubar usage */ - u32 Reserved5[27]; /* 94-FF */ + u32 Reserved5[1050];/* 94-10F8 */ + u32 Reset_1078; /* 10FC Reset 1078 */ } SYSIF_REGS; /* @@ -341,6 +342,7 @@ typedef struct _VirtTarget { u8 negoFlags; /* bit field, see above */ u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ + u8 deleted; /* target in process of being removed */ u32 num_luns; u32 luns[8]; /* Max LUNs is 256 */ } VirtTarget; @@ -629,10 +631,11 @@ typedef struct _MPT_ADAPTER struct mutex sas_discovery_mutex; u8 sas_discovery_runtime; u8 sas_discovery_ignore_events; + u16 handle; int sas_index; /* index refrencing */ MPT_SAS_MGMT sas_mgmt; int num_ports; - struct work_struct mptscsih_persistTask; + struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; struct list_head fc_rports; @@ -641,6 +644,7 @@ typedef struct _MPT_ADAPTER struct work_struct fc_rescan_work; char fc_rescan_work_q_name[KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + u8 port_serial_number; } MPT_ADAPTER; /* @@ -892,6 +896,13 @@ typedef struct _mpt_sge { #define DBG_DUMP_REQUEST_FRAME_HDR(mfp) #endif +// debug sas wide ports +#ifdef MPT_DEBUG_SAS_WIDE +#define dsaswideprintk(x) printk x +#else +#define dsaswideprintk(x) +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 3ff8378ea66..a8f2fa98545 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -132,21 +132,21 @@ static struct scsi_host_template mptfc_driver_template = { */ static struct pci_device_id mptfc_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 85689ab46cb..f7bd8b11ed3 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -50,11 +50,14 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/workqueue.h> +#include <linux/delay.h> /* for mdelay */ +#include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h> #include "mptbase.h" #include "mptscsih.h" @@ -137,23 +140,37 @@ struct mptsas_devinfo { u32 device_info; /* bitfield detailed info about this device */ }; +/* + * Specific details on ports, wide/narrow + */ +struct mptsas_portinfo_details{ + u8 port_id; /* port number provided to transport */ + u16 num_phys; /* number of phys belong to this port */ + u64 phy_bitmask; /* TODO, extend support for 255 phys */ + struct sas_rphy *rphy; /* transport layer rphy object */ + struct sas_port *port; /* transport layer port object */ + struct scsi_target *starget; + struct mptsas_portinfo *port_info; +}; + struct mptsas_phyinfo { u8 phy_id; /* phy index */ - u8 port_id; /* port number this phy is part of */ + u8 port_id; /* firmware port identifier */ u8 negotiated_link_rate; /* nego'd link rate for this phy */ u8 hw_link_rate; /* hardware max/min phys link rate */ u8 programmed_link_rate; /* programmed max/min phy link rate */ + u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ struct mptsas_devinfo identify; /* point to phy device info */ struct mptsas_devinfo attached; /* point to attached device info */ - struct sas_phy *phy; - struct sas_rphy *rphy; - struct scsi_target *starget; + struct sas_phy *phy; /* transport layer phy object */ + struct mptsas_portinfo *portinfo; + struct mptsas_portinfo_details * port_details; }; struct mptsas_portinfo { struct list_head list; u16 handle; /* unique id to address this */ - u8 num_phys; /* number of phys */ + u16 num_phys; /* number of phys */ struct mptsas_phyinfo *phy_info; }; @@ -169,7 +186,7 @@ struct mptsas_enclosure { u8 sep_channel; /* SEP channel logical channel id */ }; -#ifdef SASDEBUG +#ifdef MPT_DEBUG_SAS static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) { printk("---- IO UNIT PAGE 0 ------------\n"); @@ -305,7 +322,7 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) static inline int mptsas_is_end_device(struct mptsas_devinfo * attached) { - if ((attached->handle) && + if ((attached->sas_address) && (attached->device_info & MPI_SAS_DEVICE_INFO_END_DEVICE) && ((attached->device_info & @@ -319,6 +336,253 @@ mptsas_is_end_device(struct mptsas_devinfo * attached) return 0; } +/* no mutex */ +static void +mptsas_port_delete(struct mptsas_portinfo_details * port_details) +{ + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info; + u8 i; + + if (!port_details) + return; + + port_info = port_details->port_info; + phy_info = port_info->phy_info; + + dsaswideprintk((KERN_DEBUG "%s: [%p]: port=%02d num_phys=%02d " + "bitmask=0x%016llX\n", + __FUNCTION__, port_details, port_details->port_id, + port_details->num_phys, port_details->phy_bitmask)); + + for (i = 0; i < port_info->num_phys; i++, phy_info++) { + if(phy_info->port_details != port_details) + continue; + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + phy_info->port_details = NULL; + } + kfree(port_details); +} + +static inline struct sas_rphy * +mptsas_get_rphy(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->rphy; + else + return NULL; +} + +static inline void +mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) +{ + if (phy_info->port_details) { + phy_info->port_details->rphy = rphy; + dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy)); + } + +#ifdef MPT_DEBUG_SAS_WIDE + if (rphy) { + dev_printk(KERN_DEBUG, &rphy->dev, "add:"); + printk("rphy=%p release=%p\n", + rphy, rphy->dev.release); + } +#endif +} + +static inline struct sas_port * +mptsas_get_port(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->port; + else + return NULL; +} + +static inline void +mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port) +{ + if (phy_info->port_details) + phy_info->port_details->port = port; + +#ifdef MPT_DEBUG_SAS_WIDE + if (port) { + dev_printk(KERN_DEBUG, &port->dev, "add: "); + printk("port=%p release=%p\n", + port, port->dev.release); + } +#endif +} + +static inline struct scsi_target * +mptsas_get_starget(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->starget; + else + return NULL; +} + +static inline void +mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * +starget) +{ + if (phy_info->port_details) + phy_info->port_details->starget = starget; +} + + +/* + * mptsas_setup_wide_ports + * + * Updates for new and existing narrow/wide port configuration + * in the sas_topology + */ +static void +mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + struct mptsas_portinfo_details * port_details; + struct mptsas_phyinfo *phy_info, *phy_info_cmp; + u64 sas_address; + int i, j; + + mutex_lock(&ioc->sas_topology_mutex); + + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + if (phy_info->attached.handle) + continue; + port_details = phy_info->port_details; + if (!port_details) + continue; + if (port_details->num_phys < 2) + continue; + /* + * Removing a phy from a port, letting the last + * phy be removed by firmware events. + */ + dsaswideprintk((KERN_DEBUG + "%s: [%p]: port=%d deleting phy = %d\n", + __FUNCTION__, port_details, + port_details->port_id, i)); + port_details->num_phys--; + port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + sas_port_delete_phy(port_details->port, phy_info->phy); + phy_info->port_details = NULL; + } + + /* + * Populate and refresh the tree + */ + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + sas_address = phy_info->attached.sas_address; + dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", + i, sas_address)); + if (!sas_address) + continue; + port_details = phy_info->port_details; + /* + * Forming a port + */ + if (!port_details) { + port_details = kzalloc(sizeof(*port_details), + GFP_KERNEL); + if (!port_details) + goto out; + port_details->num_phys = 1; + port_details->port_info = port_info; + port_details->port_id = ioc->port_serial_number++; + if (phy_info->phy_id < 64 ) + port_details->phy_bitmask |= + (1 << phy_info->phy_id); + phy_info->sas_port_add_phy=1; + dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t" + "phy_id=%d sas_address=0x%018llX\n", + i, sas_address)); + phy_info->port_details = port_details; + } + + if (i == port_info->num_phys - 1) + continue; + phy_info_cmp = &port_info->phy_info[i + 1]; + for (j = i + 1 ; j < port_info->num_phys ; j++, + phy_info_cmp++) { + if (!phy_info_cmp->attached.sas_address) + continue; + if (sas_address != phy_info_cmp->attached.sas_address) + continue; + if (phy_info_cmp->port_details == port_details ) + continue; + dsaswideprintk((KERN_DEBUG + "\t\tphy_id=%d sas_address=0x%018llX\n", + j, phy_info_cmp->attached.sas_address)); + if (phy_info_cmp->port_details) { + port_details->rphy = + mptsas_get_rphy(phy_info_cmp); + port_details->port = + mptsas_get_port(phy_info_cmp); + port_details->starget = + mptsas_get_starget(phy_info_cmp); + port_details->port_id = + phy_info_cmp->port_details->port_id; + port_details->num_phys = + phy_info_cmp->port_details->num_phys; +// port_info->port_serial_number--; + ioc->port_serial_number--; + if (!phy_info_cmp->port_details->num_phys) + kfree(phy_info_cmp->port_details); + } else + phy_info_cmp->sas_port_add_phy=1; + /* + * Adding a phy to a port + */ + phy_info_cmp->port_details = port_details; + if (phy_info_cmp->phy_id < 64 ) + port_details->phy_bitmask |= + (1 << phy_info_cmp->phy_id); + port_details->num_phys++; + } + } + + out: + +#ifdef MPT_DEBUG_SAS_WIDE + for (i = 0; i < port_info->num_phys; i++) { + port_details = port_info->phy_info[i].port_details; + if (!port_details) + continue; + dsaswideprintk((KERN_DEBUG + "%s: [%p]: phy_id=%02d port_id=%02d num_phys=%02d " + "bitmask=0x%016llX\n", + __FUNCTION__, + port_details, i, port_details->port_id, + port_details->num_phys, port_details->phy_bitmask)); + dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n", + port_details->port, port_details->rphy)); + } + dsaswideprintk((KERN_DEBUG"\n")); +#endif + mutex_unlock(&ioc->sas_topology_mutex); +} + +static void +mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + + if (mptscsih_TMHandler(hd, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) { + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + printk(MYIOC_s_WARN_FMT + "Error processing TaskMgmt id=%d TARGET_RESET\n", + ioc->name, vtarget->target_id); + } +} + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -400,11 +664,105 @@ mptsas_slave_configure(struct scsi_device *sdev) return mptscsih_slave_configure(sdev); } -/* - * This is pretty ugly. We will be able to seriously clean it up - * once the DV code in mptscsih goes away and we can properly - * implement ->target_alloc. - */ +static int +mptsas_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *host = dev_to_shost(&starget->dev); + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + VirtTarget *vtarget; + u32 target_id; + u32 channel; + struct sas_rphy *rphy; + struct mptsas_portinfo *p; + int i; + + vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); + if (!vtarget) + return -ENOMEM; + + vtarget->starget = starget; + vtarget->ioc_id = hd->ioc->id; + vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; + + target_id = starget->id; + channel = 0; + + hd->Targets[target_id] = vtarget; + + /* + * RAID volumes placed beyond the last expected port. + */ + if (starget->channel == hd->ioc->num_ports) + goto out; + + rphy = dev_to_rphy(starget->dev.parent); + mutex_lock(&hd->ioc->sas_topology_mutex); + list_for_each_entry(p, &hd->ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + target_id = p->phy_info[i].attached.id; + channel = p->phy_info[i].attached.channel; + mptsas_set_starget(&p->phy_info[i], starget); + + /* + * Exposing hidden raid components + */ + if (mptscsih_is_phys_disk(hd->ioc, target_id)) { + target_id = mptscsih_raid_id_to_num(hd, + target_id); + vtarget->tflags |= + MPT_TARGET_FLAGS_RAID_COMPONENT; + } + mutex_unlock(&hd->ioc->sas_topology_mutex); + goto out; + } + } + mutex_unlock(&hd->ioc->sas_topology_mutex); + + kfree(vtarget); + return -ENXIO; + + out: + vtarget->target_id = target_id; + vtarget->bus_id = channel; + starget->hostdata = vtarget; + return 0; +} + +static void +mptsas_target_destroy(struct scsi_target *starget) +{ + struct Scsi_Host *host = dev_to_shost(&starget->dev); + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + struct sas_rphy *rphy; + struct mptsas_portinfo *p; + int i; + + if (!starget->hostdata) + return; + + if (starget->channel == hd->ioc->num_ports) + goto out; + + rphy = dev_to_rphy(starget->dev.parent); + list_for_each_entry(p, &hd->ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + mptsas_set_starget(&p->phy_info[i], NULL); + goto out; + } + } + + out: + kfree(starget->hostdata); + starget->hostdata = NULL; +} + + static int mptsas_slave_alloc(struct scsi_device *sdev) { @@ -412,61 +770,41 @@ mptsas_slave_alloc(struct scsi_device *sdev) MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; struct sas_rphy *rphy; struct mptsas_portinfo *p; - VirtTarget *vtarget; VirtDevice *vdev; struct scsi_target *starget; - u32 target_id; - int i; + int i; vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { - printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", + printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - sdev->hostdata = vdev; starget = scsi_target(sdev); - vtarget = starget->hostdata; - vtarget->ioc_id = hd->ioc->id; - vdev->vtarget = vtarget; - if (vtarget->num_luns == 0) { - vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; - hd->Targets[sdev->id] = vtarget; - } + vdev->vtarget = starget->hostdata; /* - RAID volumes placed beyond the last expected port. - */ - if (sdev->channel == hd->ioc->num_ports) { - target_id = sdev->id; - vtarget->bus_id = 0; - vdev->lun = 0; + * RAID volumes placed beyond the last expected port. + */ + if (sdev->channel == hd->ioc->num_ports) goto out; - } rphy = dev_to_rphy(sdev->sdev_target->dev.parent); mutex_lock(&hd->ioc->sas_topology_mutex); list_for_each_entry(p, &hd->ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address == - rphy->identify.sas_address) { - target_id = p->phy_info[i].attached.id; - vtarget->bus_id = p->phy_info[i].attached.channel; - vdev->lun = sdev->lun; - p->phy_info[i].starget = sdev->sdev_target; - /* - * Exposing hidden disk (RAID) - */ - if (mptscsih_is_phys_disk(hd->ioc, target_id)) { - target_id = mptscsih_raid_id_to_num(hd, - target_id); - vdev->vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - sdev->no_uld_attach = 1; - } - mutex_unlock(&hd->ioc->sas_topology_mutex); - goto out; - } + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + vdev->lun = sdev->lun; + /* + * Exposing hidden raid components + */ + if (mptscsih_is_phys_disk(hd->ioc, + p->phy_info[i].attached.id)) + sdev->no_uld_attach = 1; + mutex_unlock(&hd->ioc->sas_topology_mutex); + goto out; } } mutex_unlock(&hd->ioc->sas_topology_mutex); @@ -475,57 +813,39 @@ mptsas_slave_alloc(struct scsi_device *sdev) return -ENXIO; out: - vtarget->target_id = target_id; - vtarget->num_luns++; + vdev->vtarget->num_luns++; + sdev->hostdata = vdev; return 0; } -static void -mptsas_slave_destroy(struct scsi_device *sdev) +static int +mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; - VirtDevice *vdev; + VirtDevice *vdev = SCpnt->device->hostdata; - /* - * Issue target reset to flush firmware outstanding commands. - */ - vdev = sdev->hostdata; - if (vdev->configured_lun){ - if (mptscsih_TMHandler(hd, - MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdev->vtarget->bus_id, - vdev->vtarget->target_id, - 0, 0, 5 /* 5 second timeout */) - < 0){ - - /* The TM request failed! - * Fatal error case. - */ - printk(MYIOC_s_WARN_FMT - "Error processing TaskMgmt id=%d TARGET_RESET\n", - hd->ioc->name, - vdev->vtarget->target_id); - - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } +// scsi_print_command(SCpnt); + if (vdev->vtarget->deleted) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; } - mptscsih_slave_destroy(sdev); + + return mptscsih_qcmd(SCpnt,done); } + static struct scsi_host_template mptsas_driver_template = { .module = THIS_MODULE, .proc_name = "mptsas", .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, - .queuecommand = mptscsih_qcmd, - .target_alloc = mptscsih_target_alloc, + .queuecommand = mptsas_qcmd, + .target_alloc = mptsas_target_alloc, .slave_alloc = mptsas_slave_alloc, .slave_configure = mptsas_slave_configure, - .target_destroy = mptscsih_target_destroy, - .slave_destroy = mptsas_slave_destroy, + .target_destroy = mptsas_target_destroy, + .slave_destroy = mptscsih_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, @@ -795,7 +1115,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo),GFP_KERNEL); + sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -811,6 +1131,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) buffer->PhyData[i].Port; port_info->phy_info[i].negotiated_link_rate = buffer->PhyData[i].NegotiatedLinkRate; + port_info->phy_info[i].portinfo = port_info; } out_free_consistent: @@ -968,7 +1289,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, CONFIGPARMS cfg; SasExpanderPage0_t *buffer; dma_addr_t dma_handle; - int error; + int i, error; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1013,12 +1334,15 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, port_info->num_phys = buffer->NumPhys; port_info->handle = le16_to_cpu(buffer->DevHandle); port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo),GFP_KERNEL); + sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); @@ -1161,19 +1485,23 @@ static int mptsas_probe_one_phy(struct device *dev, { MPT_ADAPTER *ioc; struct sas_phy *phy; - int error; + struct sas_port *port; + int error = 0; - if (!dev) - return -ENODEV; + if (!dev) { + error = -ENODEV; + goto out; + } if (!phy_info->phy) { phy = sas_phy_alloc(dev, index); - if (!phy) - return -ENOMEM; + if (!phy) { + error = -ENOMEM; + goto out; + } } else phy = phy_info->phy; - phy->port_identifier = phy_info->port_id; mptsas_parse_device_info(&phy->identify, &phy_info->identify); /* @@ -1265,19 +1593,52 @@ static int mptsas_probe_one_phy(struct device *dev, error = sas_phy_add(phy); if (error) { sas_phy_free(phy); - return error; + goto out; } phy_info->phy = phy; } - if ((phy_info->attached.handle) && - (!phy_info->rphy)) { + if (!phy_info->attached.handle || + !phy_info->port_details) + goto out; + + port = mptsas_get_port(phy_info); + ioc = phy_to_ioc(phy_info->phy); + + if (phy_info->sas_port_add_phy) { + + if (!port) { + port = sas_port_alloc(dev, + phy_info->port_details->port_id); + dsaswideprintk((KERN_DEBUG + "sas_port_alloc: port=%p dev=%p port_id=%d\n", + port, dev, phy_info->port_details->port_id)); + if (!port) { + error = -ENOMEM; + goto out; + } + error = sas_port_add(port); + if (error) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + goto out; + } + mptsas_set_port(phy_info, port); + } + dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n", + phy_info->phy_id)); + sas_port_add_phy(port, phy_info->phy); + phy_info->sas_port_add_phy = 0; + } + + if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; + struct device *parent; struct sas_identify identify; - ioc = phy_to_ioc(phy_info->phy); - + parent = dev->parent->parent; /* * Let the hotplug_work thread handle processing * the adding/removing of devices that occur @@ -1285,36 +1646,63 @@ static int mptsas_probe_one_phy(struct device *dev, */ if (ioc->sas_discovery_runtime && mptsas_is_end_device(&phy_info->attached)) - return 0; + goto out; mptsas_parse_device_info(&identify, &phy_info->attached); + if (scsi_is_host_device(parent)) { + struct mptsas_portinfo *port_info; + int i; + + mutex_lock(&ioc->sas_topology_mutex); + port_info = mptsas_find_portinfo_by_handle(ioc, + ioc->handle); + mutex_unlock(&ioc->sas_topology_mutex); + + for (i = 0; i < port_info->num_phys; i++) + if (port_info->phy_info[i].identify.sas_address == + identify.sas_address) + goto out; + + } else if (scsi_is_sas_rphy(parent)) { + struct sas_rphy *parent_rphy = dev_to_rphy(parent); + if (identify.sas_address == + parent_rphy->identify.sas_address) + goto out; + } + switch (identify.device_type) { case SAS_END_DEVICE: - rphy = sas_end_device_alloc(phy); + rphy = sas_end_device_alloc(port); break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: - rphy = sas_expander_alloc(phy, identify.device_type); + rphy = sas_expander_alloc(port, identify.device_type); break; default: rphy = NULL; break; } - if (!rphy) - return 0; /* non-fatal: an rphy can be added later */ + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + goto out; + } rphy->identify = identify; - error = sas_rphy_add(rphy); if (error) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); sas_rphy_free(rphy); - return error; + goto out; } - - phy_info->rphy = rphy; + mptsas_set_rphy(phy_info, rphy); } - return 0; + out: + return error; } static int @@ -1333,6 +1721,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) goto out_free_port_info; mutex_lock(&ioc->sas_topology_mutex); + ioc->handle = hba->handle; port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); if (!port_info) { port_info = hba; @@ -1342,8 +1731,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) for (i = 0; i < hba->num_phys; i++) port_info->phy_info[i].negotiated_link_rate = hba->phy_info[i].negotiated_link_rate; - if (hba->phy_info) - kfree(hba->phy_info); + kfree(hba->phy_info); kfree(hba); hba = NULL; } @@ -1362,18 +1750,19 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) port_info->phy_info[i].phy_id; handle = port_info->phy_info[i].identify.handle; - if (port_info->phy_info[i].attached.handle) { + if (port_info->phy_info[i].attached.handle) mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].attached, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].attached.handle); - } + } + + mptsas_setup_wide_ports(ioc, port_info); + for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(&ioc->sh->shost_gendev, &port_info->phy_info[i], ioc->sas_index, 1); - ioc->sas_index++; - } return 0; @@ -1387,6 +1776,8 @@ static int mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) { struct mptsas_portinfo *port_info, *p, *ex; + struct device *parent; + struct sas_rphy *rphy; int error = -ENOMEM, i, j; ex = kzalloc(sizeof(*port_info), GFP_KERNEL); @@ -1408,16 +1799,13 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) list_add_tail(&port_info->list, &ioc->sas_topology); } else { port_info->handle = ex->handle; - if (ex->phy_info) - kfree(ex->phy_info); + kfree(ex->phy_info); kfree(ex); ex = NULL; } mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) { - struct device *parent; - mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); @@ -1441,34 +1829,34 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) port_info->phy_info[i].attached.phy_id = port_info->phy_info[i].phy_id; } + } - /* - * If we find a parent port handle this expander is - * attached to another expander, else it hangs of the - * HBA phys. - */ - parent = &ioc->sh->shost_gendev; + parent = &ioc->sh->shost_gendev; + for (i = 0; i < port_info->num_phys; i++) { mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(p, &ioc->sas_topology, list) { for (j = 0; j < p->num_phys; j++) { - if (port_info->phy_info[i].identify.handle == + if (port_info->phy_info[i].identify.handle != p->phy_info[j].attached.handle) - parent = &p->phy_info[j].rphy->dev; + continue; + rphy = mptsas_get_rphy(&p->phy_info[j]); + parent = &rphy->dev; } } mutex_unlock(&ioc->sas_topology_mutex); + } + + mptsas_setup_wide_ports(ioc, port_info); + for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(parent, &port_info->phy_info[i], ioc->sas_index, 0); - ioc->sas_index++; - } return 0; out_free_port_info: if (ex) { - if (ex->phy_info) - kfree(ex->phy_info); + kfree(ex->phy_info); kfree(ex); } out: @@ -1487,7 +1875,12 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) { struct mptsas_portinfo buffer; struct mptsas_portinfo *port_info, *n, *parent; + struct mptsas_phyinfo *phy_info; + struct scsi_target * starget; + VirtTarget * vtarget; + struct sas_port * port; int i; + u64 expander_sas_address; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { @@ -1502,6 +1895,25 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { /* + * Issue target reset to all child end devices + * then mark them deleted to prevent further + * IO going to them. + */ + phy_info = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info++) { + starget = mptsas_get_starget(phy_info); + if (!starget) + continue; + vtarget = starget->hostdata; + if(vtarget->deleted) + continue; + vtarget->deleted = 1; + mptsas_target_reset(ioc, vtarget); + sas_port_delete(mptsas_get_port(phy_info)); + mptsas_port_delete(phy_info->port_details); + } + + /* * Obtain the port_info instance to the parent port */ parent = mptsas_find_portinfo_by_handle(ioc, @@ -1510,34 +1922,43 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) if (!parent) goto next_port; + expander_sas_address = + port_info->phy_info[0].identify.sas_address; + /* * Delete rphys in the parent that point * to this expander. The transport layer will * cleanup all the children. */ - for (i = 0; i < parent->num_phys; i++) { - if ((!parent->phy_info[i].rphy) || - (parent->phy_info[i].attached.sas_address != - port_info->phy_info[i].identify.sas_address)) + phy_info = parent->phy_info; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + port = mptsas_get_port(phy_info); + if (!port) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) continue; - sas_rphy_delete(parent->phy_info[i].rphy); - memset(&parent->phy_info[i].attached, 0, - sizeof(struct mptsas_devinfo)); - parent->phy_info[i].rphy = NULL; - parent->phy_info[i].starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE + dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif + sas_port_delete(port); + mptsas_port_delete(phy_info->port_details); } next_port: + + phy_info = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info++) + mptsas_port_delete(phy_info->port_details); + list_del(&port_info->list); - if (port_info->phy_info) - kfree(port_info->phy_info); + kfree(port_info->phy_info); kfree(port_info); } /* * Free this memory allocated from inside * mptsas_sas_expander_pg0 */ - if (buffer.phy_info) - kfree(buffer.phy_info); + kfree(buffer.phy_info); } mutex_unlock(&ioc->sas_topology_mutex); } @@ -1573,60 +1994,59 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc) /* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders + *(Mutex UNLOCKED) */ static void -mptscsih_discovery_work(void * arg) +__mptsas_discovery_work(MPT_ADAPTER *ioc) { - struct mptsas_discovery_event *ev = arg; - MPT_ADAPTER *ioc = ev->ioc; u32 handle = 0xFFFF; - mutex_lock(&ioc->sas_discovery_mutex); ioc->sas_discovery_runtime=1; mptsas_delete_expander_phys(ioc); mptsas_probe_hba_phys(ioc); while (!mptsas_probe_expander_phys(ioc, &handle)) ; - kfree(ev); ioc->sas_discovery_runtime=0; +} + +/* + * Work queue thread to handle Runtime discovery + * Mere purpose is the hot add/delete of expanders + *(Mutex LOCKED) + */ +static void +mptsas_discovery_work(void * arg) +{ + struct mptsas_discovery_event *ev = arg; + MPT_ADAPTER *ioc = ev->ioc; + + mutex_lock(&ioc->sas_discovery_mutex); + __mptsas_discovery_work(ioc); mutex_unlock(&ioc->sas_discovery_mutex); + kfree(ev); } static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) +mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) { struct mptsas_portinfo *port_info; - struct mptsas_devinfo device_info; struct mptsas_phyinfo *phy_info = NULL; - int i, error; - - /* - * Retrieve the parent sas_address - */ - error = mptsas_sas_device_pg0(ioc, &device_info, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - parent_handle); - if (error) - return NULL; + int i; - /* - * The phy_info structures are never deallocated during lifetime of - * a host, so the code below is safe without additional refcounting. - */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { for (i = 0; i < port_info->num_phys; i++) { - if (port_info->phy_info[i].identify.sas_address == - device_info.sas_address && - port_info->phy_info[i].phy_id == phy_id) { - phy_info = &port_info->phy_info[i]; - break; - } + if (port_info->phy_info[i].attached.sas_address + != sas_address) + continue; + if (!mptsas_is_end_device( + &port_info->phy_info[i].attached)) + continue; + phy_info = &port_info->phy_info[i]; + break; } } mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; } @@ -1637,21 +2057,19 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) struct mptsas_phyinfo *phy_info = NULL; int i; - /* - * The phy_info structures are never deallocated during lifetime of - * a host, so the code below is safe without additional refcounting. - */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) - if (mptsas_is_end_device(&port_info->phy_info[i].attached)) - if (port_info->phy_info[i].attached.id == id) { - phy_info = &port_info->phy_info[i]; - break; - } + for (i = 0; i < port_info->num_phys; i++) { + if (port_info->phy_info[i].attached.id != id) + continue; + if (!mptsas_is_end_device( + &port_info->phy_info[i].attached)) + continue; + phy_info = &port_info->phy_info[i]; + break; + } } mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; } @@ -1659,7 +2077,7 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) * Work queue thread to clear the persitency table */ static void -mptscsih_sas_persist_clear_table(void * arg) +mptsas_persist_clear_table(void * arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; @@ -1680,7 +2098,6 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) mptsas_reprobe_lun); } - /* * Work queue thread to handle SAS hotplug events */ @@ -1691,14 +2108,17 @@ mptsas_hotplug_work(void *arg) MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; + struct sas_port *port; struct scsi_device *sdev; + struct scsi_target * starget; struct sas_identify identify; char *ds = NULL; struct mptsas_devinfo sas_device; VirtTarget *vtarget; + VirtDevice *vdevice; - mutex_lock(&ioc->sas_discovery_mutex); + mutex_lock(&ioc->sas_discovery_mutex); switch (ev->event_type) { case MPTSAS_DEL_DEVICE: @@ -1707,24 +2127,50 @@ mptsas_hotplug_work(void *arg) /* * Sanity checks, for non-existing phys and remote rphys. */ - if (!phy_info) + if (!phy_info || !phy_info->port_details) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; - if (!phy_info->rphy) + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; - if (phy_info->starget) { - vtarget = phy_info->starget->hostdata; + } + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } - if (!vtarget) + starget = mptsas_get_starget(phy_info); + if (starget) { + vtarget = starget->hostdata; + + if (!vtarget) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } + /* * Handling RAID components */ if (ev->phys_disk_num_valid) { vtarget->target_id = ev->phys_disk_num; vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - mptsas_reprobe_target(vtarget->starget, 1); + mptsas_reprobe_target(starget, 1); break; } + + vtarget->deleted = 1; + mptsas_target_reset(ioc, vtarget); } if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) @@ -1738,10 +2184,11 @@ mptsas_hotplug_work(void *arg) "removing %s device, channel %d, id %d, phy %d\n", ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - sas_rphy_delete(phy_info->rphy); - memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - phy_info->rphy = NULL; - phy_info->starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE + dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif + sas_port_delete(port); + mptsas_port_delete(phy_info->port_details); break; case MPTSAS_ADD_DEVICE: @@ -1753,59 +2200,60 @@ mptsas_hotplug_work(void *arg) */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } - phy_info = mptsas_find_phyinfo_by_parent(ioc, - sas_device.handle_parent, sas_device.phy_id); + ssleep(2); + __mptsas_discovery_work(ioc); - if (!phy_info) { - u32 handle = 0xFFFF; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); - /* - * Its possible when an expander has been hot added - * containing attached devices, the sas firmware - * may send a RC_ADDED event prior to the - * DISCOVERY STOP event. If that occurs, our - * view of the topology in the driver in respect to this - * expander might of not been setup, and we hit this - * condition. - * Therefore, this code kicks off discovery to - * refresh the data. - * Then again, we check whether the parent phy has - * been created. - */ - ioc->sas_discovery_runtime=1; - mptsas_delete_expander_phys(ioc); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - ioc->sas_discovery_runtime=0; - - phy_info = mptsas_find_phyinfo_by_parent(ioc, - sas_device.handle_parent, sas_device.phy_id); - if (!phy_info) - break; + if (!phy_info || !phy_info->port_details) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; } - if (phy_info->starget) { - vtarget = phy_info->starget->hostdata; + starget = mptsas_get_starget(phy_info); + if (starget) { + vtarget = starget->hostdata; - if (!vtarget) + if (!vtarget) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } /* * Handling RAID components */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; vtarget->target_id = ev->id; - mptsas_reprobe_target(phy_info->starget, 0); + mptsas_reprobe_target(starget, 0); } break; } - if (phy_info->rphy) + if (mptsas_get_rphy(phy_info)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } memcpy(&phy_info->attached, &sas_device, sizeof(struct mptsas_devinfo)); @@ -1822,28 +2270,23 @@ mptsas_hotplug_work(void *arg) ioc->name, ds, ev->channel, ev->id, ev->phy_id); mptsas_parse_device_info(&identify, &phy_info->attached); - switch (identify.device_type) { - case SAS_END_DEVICE: - rphy = sas_end_device_alloc(phy_info->phy); - break; - case SAS_EDGE_EXPANDER_DEVICE: - case SAS_FANOUT_EXPANDER_DEVICE: - rphy = sas_expander_alloc(phy_info->phy, identify.device_type); - break; - default: - rphy = NULL; - break; - } - if (!rphy) + rphy = sas_end_device_alloc(port); + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; /* non-fatal: an rphy can be added later */ + } rphy->identify = identify; if (sas_rphy_add(rphy)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); sas_rphy_free(rphy); break; } - - phy_info->rphy = rphy; + mptsas_set_rphy(phy_info, rphy); break; case MPTSAS_ADD_RAID: sdev = scsi_device_lookup( @@ -1875,6 +2318,9 @@ mptsas_hotplug_work(void *arg) printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, id %d\n", ioc->name, ioc->num_ports, ev->id); + vdevice = sdev->hostdata; + vdevice->vtarget->deleted = 1; + mptsas_target_reset(ioc, vdevice->vtarget); scsi_remove_device(sdev); scsi_device_put(sdev); mpt_findImVolumes(ioc); @@ -1884,12 +2330,13 @@ mptsas_hotplug_work(void *arg) break; } - kfree(ev); mutex_unlock(&ioc->sas_discovery_mutex); + kfree(ev); + } static void -mptscsih_send_sas_event(MPT_ADAPTER *ioc, +mptsas_send_sas_event(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) { struct mptsas_hotplug_event *ev; @@ -1905,7 +2352,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, switch (sas_event_data->ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); break; @@ -1935,10 +2382,9 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, /* * Persistent table is full. */ - INIT_WORK(&ioc->mptscsih_persistTask, - mptscsih_sas_persist_clear_table, - (void *)ioc); - schedule_work(&ioc->mptscsih_persistTask); + INIT_WORK(&ioc->sas_persist_task, + mptsas_persist_clear_table, (void *)ioc); + schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: /* TODO */ @@ -1950,7 +2396,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, } static void -mptscsih_send_raid_event(MPT_ADAPTER *ioc, +mptsas_send_raid_event(MPT_ADAPTER *ioc, EVENT_DATA_RAID *raid_event_data) { struct mptsas_hotplug_event *ev; @@ -1960,13 +2406,12 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, if (ioc->bus_type != SAS) return; - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); return; } - memset(ev,0,sizeof(struct mptsas_hotplug_event)); INIT_WORK(&ev->work, mptsas_hotplug_work, ev); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; @@ -2028,7 +2473,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, } static void -mptscsih_send_discovery(MPT_ADAPTER *ioc, +mptsas_send_discovery_event(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DISCOVERY *discovery_data) { struct mptsas_discovery_event *ev; @@ -2043,11 +2488,10 @@ mptscsih_send_discovery(MPT_ADAPTER *ioc, if (discovery_data->DiscoveryStatus) return; - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return; - memset(ev,0,sizeof(struct mptsas_discovery_event)); - INIT_WORK(&ev->work, mptscsih_discovery_work, ev); + INIT_WORK(&ev->work, mptsas_discovery_work, ev); ev->ioc = ioc; schedule_work(&ev->work); }; @@ -2075,21 +2519,21 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) switch (event) { case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptscsih_send_sas_event(ioc, + mptsas_send_sas_event(ioc, (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); break; case MPI_EVENT_INTEGRATED_RAID: - mptscsih_send_raid_event(ioc, + mptsas_send_raid_event(ioc, (EVENT_DATA_RAID *)reply->Data); break; case MPI_EVENT_PERSISTENT_TABLE_FULL: - INIT_WORK(&ioc->mptscsih_persistTask, - mptscsih_sas_persist_clear_table, + INIT_WORK(&ioc->sas_persist_task, + mptsas_persist_clear_table, (void *)ioc); - schedule_work(&ioc->mptscsih_persistTask); + schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DISCOVERY: - mptscsih_send_discovery(ioc, + mptsas_send_discovery_event(ioc, (EVENT_DATA_SAS_DISCOVERY *)reply->Data); break; default: @@ -2308,7 +2752,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; -out_mptsas_probe: + out_mptsas_probe: mptscsih_remove(pdev); return error; @@ -2318,6 +2762,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptsas_portinfo *p, *n; + int i; ioc->sas_discovery_ignore_events=1; sas_remove_host(ioc->sh); @@ -2325,8 +2770,9 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { list_del(&p->list); - if (p->phy_info) - kfree(p->phy_info); + for (i = 0 ; i < p->num_phys ; i++) + mptsas_port_delete(p->phy_info[i].port_details); + kfree(p->phy_info); kfree(p); } mutex_unlock(&ioc->sas_topology_mutex); @@ -2335,17 +2781,15 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) } static struct pci_device_id mptsas_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 3201de05394..0a1ff762205 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -775,9 +775,9 @@ static struct spi_function_template mptspi_transport_functions = { */ static struct pci_device_id mptspi_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index eb7a6a4ded7..657a3ab7539 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -173,6 +173,7 @@ STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); +STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); @@ -182,10 +183,6 @@ STATIC struct device_attribute *NCR_700_dev_attrs[]; STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; -struct NCR_700_sense { - unsigned char cmnd[MAX_COMMAND_SIZE]; -}; - static char *NCR_700_phase[] = { "", "after selection", @@ -333,6 +330,7 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->use_clustering = ENABLE_CLUSTERING; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; + tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; tpnt->change_queue_type = NCR_700_change_queue_type; @@ -611,9 +609,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - NCR_700_unmap(hostdata, SCp, slot); + dma_unmap_single(hostdata->dev, slot->pCmd, + sizeof(SCp->cmnd), DMA_TO_DEVICE); if (slot->flags == NCR_700_FLAG_AUTOSENSE) { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_700_DEBUG printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", SCp, SCp->cmnd[7], result); @@ -624,10 +623,9 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, /* restore the old result if the request sense was * successful */ if(result == 0) - result = sense->cmnd[7]; + result = cmnd[7]; } else - dma_unmap_single(hostdata->dev, slot->pCmd, - sizeof(SCp->cmnd), DMA_TO_DEVICE); + NCR_700_unmap(hostdata, SCp, slot); free_slot(slot, hostdata); #ifdef NCR_700_DEBUG @@ -969,14 +967,15 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - if(SCp->cmnd[0] == REQUEST_SENSE) { + if(slot->flags == NCR_700_FLAG_AUTOSENSE) { /* OOPS: bad device, returning another * contingent allegiance condition */ scmd_printk(KERN_ERR, SCp, "broken device is looping in contingent allegiance: ignoring\n"); NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } else { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = + NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_DEBUG scsi_print_command(SCp); printk(" cmd %p has status %d, requesting sense\n", @@ -994,21 +993,21 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, sizeof(SCp->cmnd), DMA_TO_DEVICE); - sense->cmnd[0] = REQUEST_SENSE; - sense->cmnd[1] = (SCp->device->lun & 0x7) << 5; - sense->cmnd[2] = 0; - sense->cmnd[3] = 0; - sense->cmnd[4] = sizeof(SCp->sense_buffer); - sense->cmnd[5] = 0; + cmnd[0] = REQUEST_SENSE; + cmnd[1] = (SCp->device->lun & 0x7) << 5; + cmnd[2] = 0; + cmnd[3] = 0; + cmnd[4] = sizeof(SCp->sense_buffer); + cmnd[5] = 0; /* Here's a quiet hack: the * REQUEST_SENSE command is six bytes, * so store a flag indicating that * this was an internal sense request * and the original status at the end * of the command */ - sense->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; - sense->cmnd[7] = hostdata->status[0]; - slot->pCmd = dma_map_single(hostdata->dev, sense->cmnd, sizeof(sense->cmnd), DMA_TO_DEVICE); + cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; + cmnd[7] = hostdata->status[0]; + slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); @@ -1530,7 +1529,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs) /* clear all the negotiated parameters */ __shost_for_each_device(SDp, host) - SDp->hostdata = NULL; + NCR_700_clear_flag(SDp, ~0); /* clear all the slots and their pending commands */ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { @@ -2035,7 +2034,17 @@ NCR_700_set_offset(struct scsi_target *STp, int offset) spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; } +STATIC int +NCR_700_slave_alloc(struct scsi_device *SDp) +{ + SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), + GFP_KERNEL); + if (!SDp->hostdata) + return -ENOMEM; + + return 0; +} STATIC int NCR_700_slave_configure(struct scsi_device *SDp) @@ -2043,11 +2052,6 @@ NCR_700_slave_configure(struct scsi_device *SDp) struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense)); - - if (!SDp->hostdata) - return -ENOMEM; - /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { scsi_set_tag_type(SDp, MSG_ORDERED_TAG); diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index 7f22a06fe5e..97ebe71b701 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -12,7 +12,7 @@ #include <asm/io.h> #include <scsi/scsi_device.h> - +#include <scsi/scsi_cmnd.h> /* Turn on for general debugging---too verbose for normal use */ #undef NCR_700_DEBUG @@ -76,11 +76,16 @@ struct NCR_700_SG_List { #define SCRIPT_RETURN 0x90080000 }; -/* We use device->hostdata to store negotiated parameters. This is - * supposed to be a pointer to a device private area, but we cannot - * really use it as such since it will never be freed, so just use the - * 32 bits to cram the information. The SYNC negotiation sequence looks - * like: +struct NCR_700_Device_Parameters { + /* space for creating a request sense command. Really, except + * for the annoying SCSI-2 requirement for LUN information in + * cmnd[1], this could be in static storage */ + unsigned char cmnd[MAX_COMMAND_SIZE]; + __u8 depth; +}; + + +/* The SYNC negotiation sequence looks like: * * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION @@ -98,19 +103,26 @@ struct NCR_700_SG_List { #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) #define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) +static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp) +{ + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->cmnd; +} + static inline void NCR_700_set_depth(struct scsi_device *SDp, __u8 depth) { - long l = (long)SDp->hostdata; + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - l &= 0xffff00ff; - l |= 0xff00 & (depth << 8); - SDp->hostdata = (void *)l; + hostdata->depth = depth; } static inline __u8 NCR_700_get_depth(struct scsi_device *SDp) { - return ((((unsigned long)SDp->hostdata) & 0xff00)>>8); + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->depth; } static inline int NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag) diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 7cea514e810..1cd3584ba7f 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -92,31 +92,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); init->AdapterFibsSize = cpu_to_le32(fibsize); init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - /* - * number of 4k pages of host physical memory. The aacraid fw needs - * this number to be less than 4gb worth of pages. num_physpages is in - * system page units. New firmware doesn't have any issues with the - * mapping system, but older Firmware did, and had *troubles* dealing - * with the math overloading past 32 bits, thus we must limit this - * field. - * - * This assumes the memory is mapped zero->n, which isnt - * always true on real computers. It also has some slight problems - * with the GART on x86-64. I've btw never tried DMA from PCI space - * on this platform but don't be surprised if its problematic. - * [AK: something is very very wrong when a driver tests this symbol. - * Someone should figure out what the comment writer really meant here and fix - * the code. Or just remove that bad code. ] - */ -#ifndef CONFIG_IOMMU - if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) { - init->HostPhysMemPages = - cpu_to_le32(num_physpages << (PAGE_SHIFT-12)); - } else -#endif - { - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); - } + init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); init->InitFlags = 0; if (dev->new_comm_interface) { diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index eb774569268..df3346b5caf 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1487,6 +1487,7 @@ typedef enum { } ahd_queue_alg; void ahd_set_tags(struct ahd_softc *ahd, + struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, ahd_queue_alg alg); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 801fc81d0b2..a1e8ca75859 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -1090,7 +1090,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) /* Notify XPT */ ahd_send_async(ahd, devinfo.channel, devinfo.target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); /* * Allow the sequencer to continue with @@ -3062,7 +3062,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.ppr_options = ppr_options; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { if (offset != 0) { int options; @@ -3184,7 +3184,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.width = width; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahd_name(ahd), devinfo->target, @@ -3211,12 +3211,14 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, * Update the current state of tagged queuing for a given target. */ void -ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - ahd_platform_set_tags(ahd, devinfo, alg); + struct scsi_device *sdev = cmd->device; + + ahd_platform_set_tags(ahd, sdev, devinfo, alg); ahd_send_async(ahd, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG, &alg); + devinfo->lun, AC_TRANSFER_NEG); } static void @@ -4746,7 +4748,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) printf("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); mask = ~0x23; } else { printf("(%s:%c:%d:%d): refuses %s tagged commands. " @@ -4754,7 +4756,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK ? "ordered" : "head of queue"); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC); mask = ~0x03; } @@ -5098,7 +5100,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if (status != CAM_SEL_TIMEOUT) ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && bootverbose) printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), @@ -7952,7 +7954,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); + CAM_LUN_WILDCARD, AC_BUS_RESET); /* * Revert to async/narrow transfers until we renegotiate. diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index e0ccdf36220..b244c712417 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -484,7 +484,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) struct seeprom_config *sc = ahd->seep_config; unsigned long flags; struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -495,7 +494,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) BUG_ON(*ahd_targp != NULL); *ahd_targp = starget; - memset(targ, 0, sizeof(*targ)); if (sc) { int flags = sc->device_flags[starget->id]; @@ -551,15 +549,11 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) { struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); - struct scsi_target *starget = sdev->sdev_target; - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); - BUG_ON(targ->sdev[sdev->lun] != NULL); - dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -576,8 +570,6 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) */ dev->maxtags = 0; - targ->sdev[sdev->lun] = sdev; - return (0); } @@ -599,23 +591,6 @@ ahd_linux_slave_configure(struct scsi_device *sdev) return 0; } -static void -ahd_linux_slave_destroy(struct scsi_device *sdev) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); - - ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (bootverbose) - printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); - - BUG_ON(dev->active); - - targ->sdev[sdev->lun] = NULL; - -} - #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. @@ -822,7 +797,6 @@ struct scsi_host_template aic79xx_driver_template = { .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, - .slave_destroy = ahd_linux_slave_destroy, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, }; @@ -1249,20 +1223,13 @@ void ahd_platform_free(struct ahd_softc *ahd) { struct scsi_target *starget; - int i, j; + int i; if (ahd->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHD_NUM_TARGETS; i++) { starget = ahd->platform_data->starget[i]; if (starget != NULL) { - for (j = 0; j < AHD_NUM_LUNS; j++) { - struct ahd_linux_target *targ = - scsi_transport_target_data(starget); - if (targ->sdev[j] == NULL) - continue; - targ->sdev[j] = NULL; - } ahd->platform_data->starget[i] = NULL; } } @@ -1318,20 +1285,13 @@ ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) } void -ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - struct scsi_target *starget; - struct ahd_linux_target *targ; struct ahd_linux_device *dev; - struct scsi_device *sdev; int was_queuing; int now_queuing; - starget = ahd->platform_data->starget[devinfo->target]; - targ = scsi_transport_target_data(starget); - BUG_ON(targ == NULL); - sdev = targ->sdev[devinfo->lun]; if (sdev == NULL) return; @@ -1467,11 +1427,15 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) tags = ahd_linux_user_tagdepth(ahd, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); ahd_print_devinfo(ahd, &devinfo); printf("Tagged Queuing enabled. Depth %d\n", tags); } else { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); } } @@ -1629,7 +1593,7 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) void ahd_send_async(struct ahd_softc *ahd, char channel, - u_int target, u_int lun, ac_code code, void *arg) + u_int target, u_int lun, ac_code code) { switch (code) { case AC_TRANSFER_NEG: @@ -1956,7 +1920,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, } ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; @@ -1966,7 +1930,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, * as if the target returned BUSY SCSI status. */ dev->openings = 1; - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); @@ -2778,8 +2742,6 @@ ahd_linux_init(void) if (!ahd_linux_transport_template) return -ENODEV; - scsi_transport_reserve_target(ahd_linux_transport_template, - sizeof(struct ahd_linux_target)); scsi_transport_reserve_device(ahd_linux_transport_template, sizeof(struct ahd_linux_device)); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 92c6154575e..9e871de2383 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -262,7 +262,6 @@ typedef enum { AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ } ahd_linux_dev_flags; -struct ahd_linux_target; struct ahd_linux_device { TAILQ_ENTRY(ahd_linux_device) links; @@ -342,12 +341,6 @@ struct ahd_linux_device { #define AHD_OTAG_THRESH 500 }; -struct ahd_linux_target { - struct scsi_device *sdev[AHD_NUM_LUNS]; - struct ahd_transinfo last_tinfo; - struct ahd_softc *ahd; -}; - /********************* Definitions Required by the Core ***********************/ /* * Number of SG segments we require. So long as the S/G segments for @@ -864,7 +857,7 @@ ahd_freeze_scb(struct scb *scb) } } -void ahd_platform_set_tags(struct ahd_softc *ahd, +void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, struct ahd_devinfo *devinfo, ahd_queue_alg); int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, @@ -873,7 +866,7 @@ irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahd_done(struct ahd_softc*, struct scb*); void ahd_send_async(struct ahd_softc *, char channel, - u_int target, u_int lun, ac_code, void *); + u_int target, u_int lun, ac_code); void ahd_print_path(struct ahd_softc *, struct scb *); #ifdef CONFIG_PCI diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 24fd59a230b..c5f0ee59150 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -47,7 +47,7 @@ static int copy_info(struct info_str *info, char *fmt, ...); static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, u_int our_id, char channel, - u_int target_id, u_int target_offset); + u_int target_id); static void ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, @@ -204,10 +204,8 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, - u_int our_id, char channel, u_int target_id, - u_int target_offset) + u_int our_id, char channel, u_int target_id) { - struct ahd_linux_target *targ; struct scsi_target *starget; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -218,10 +216,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "Target %d Negotiation Settings\n", target_id); copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); - starget = ahd->platform_data->starget[target_offset]; + starget = ahd->platform_data->starget[target_id]; if (starget == NULL) return; - targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahd_format_transinfo(info, &tinfo->goal); @@ -231,7 +228,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, for (lun = 0; lun < AHD_NUM_LUNS; lun++) { struct scsi_device *dev; - dev = targ->sdev[lun]; + dev = scsi_device_lookup_by_target(starget, lun); if (dev == NULL) continue; @@ -355,7 +352,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", ahd->scb_data.numscbs, AHD_NSEG); - max_targ = 15; + max_targ = 16; if (ahd->seep_config == NULL) copy_info(&info, "No Serial EEPROM\n"); @@ -373,12 +370,12 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "\n"); if ((ahd->features & AHD_WIDE) == 0) - max_targ = 7; + max_targ = 8; - for (i = 0; i <= max_targ; i++) { + for (i = 0; i < max_targ; i++) { ahd_dump_target_state(ahd, &info, ahd->our_id, 'A', - /*target_id*/i, /*target_offset*/i); + /*target_id*/i); } retval = info.pos > info.offset ? info.pos - info.offset : 0; done: diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 412f8301b75..0ec41f34f46 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -2625,29 +2625,32 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int base_io, tmport, error,n; unsigned char host_id; struct Scsi_Host *shpnt = NULL; - struct atp_unit atp_dev, *p; + struct atp_unit *atpdev, *p; unsigned char setupdata[2][16]; int count = 0; - + + atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL); + if (!atpdev) + return -ENOMEM; + if (pci_enable_device(pdev)) - return -EIO; + goto err_eio; if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_INFO "atp870u: use 32bit DMA mask.\n"); } else { printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); - return -EIO; + goto err_eio; } - memset(&atp_dev, 0, sizeof atp_dev); /* * It's probably easier to weed out some revisions like * this than via the PCI device table */ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); - if (atp_dev.chip_ver < 2) - return -EIO; + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); + if (atpdev->chip_ver < 2) + goto err_eio; } switch (ent->device) { @@ -2656,15 +2659,15 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case ATP880_DEVID1: case ATP880_DEVID2: case ATP885_DEVID: - atp_dev.chip_ver = 0x04; + atpdev->chip_ver = 0x04; default: break; } base_io = pci_resource_start(pdev, 0); base_io &= 0xfffffff8; - + if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803 host_id = inb(base_io + 0x39); @@ -2672,17 +2675,17 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d" " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io + 0x40; - atp_dev.pciport[0] = base_io + 0x28; - atp_dev.dev_id = ent->device; - atp_dev.host_id[0] = host_id; + atpdev->ioport[0] = base_io + 0x40; + atpdev->pciport[0] = base_io + 0x28; + atpdev->dev_id = ent->device; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x13; - atp_dev.global_map[0] = inb(tmport); + atpdev->global_map[0] = inb(tmport); tmport += 0x07; - atp_dev.ultra_map[0] = inw(tmport); + atpdev->ultra_map[0] = inw(tmport); n = 0x3f09; next_fblk_880: @@ -2695,57 +2698,57 @@ next_fblk_880: if (inb(base_io + 0x30) == 0xff) goto flash_ok_880; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); n += 0x0018; goto next_fblk_880; flash_ok_880: outw(0, base_io + 0x34); - atp_dev.ultra_map[0] = 0; - atp_dev.async[0] = 0; + atpdev->ultra_map[0] = 0; + atpdev->async[0] = 0; for (k = 0; k < 16; k++) { n = 1; n = n << k; - if (atp_dev.sp[0][k] > 1) { - atp_dev.ultra_map[0] |= n; + if (atpdev->sp[0][k] > 1) { + atpdev->ultra_map[0] |= n; } else { - if (atp_dev.sp[0][k] == 0) - atp_dev.async[0] |= n; + if (atpdev->sp[0][k] == 0) + atpdev->async[0] |= n; } } - atp_dev.async[0] = ~(atp_dev.async[0]); - outb(atp_dev.global_map[0], base_io + 0x35); + atpdev->async[0] = ~(atpdev->async[0]); + outb(atpdev->global_map[0], base_io + 0x35); shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) { printk(KERN_ERR "Unable to allocate tables for Acard controller\n"); goto unregister; @@ -2798,24 +2801,24 @@ flash_ok_880: printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n" , base_io, pdev->irq); - atp_dev.pdev = pdev; - atp_dev.dev_id = ent->device; - atp_dev.baseport = base_io; - atp_dev.ioport[0] = base_io + 0x80; - atp_dev.ioport[1] = base_io + 0xc0; - atp_dev.pciport[0] = base_io + 0x40; - atp_dev.pciport[1] = base_io + 0x50; + atpdev->pdev = pdev; + atpdev->dev_id = ent->device; + atpdev->baseport = base_io; + atpdev->ioport[0] = base_io + 0x80; + atpdev->ioport[1] = base_io + 0xc0; + atpdev->pciport[0] = base_io + 0x40; + atpdev->pciport[1] = base_io + 0x50; shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof(struct atp_unit)); + memcpy(p, atpdev, sizeof(struct atp_unit)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -2974,33 +2977,33 @@ flash_ok_885: printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d " "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io; - atp_dev.pciport[0] = base_io + 0x20; - atp_dev.dev_id = ent->device; + atpdev->ioport[0] = base_io; + atpdev->pciport[0] = base_io + 0x20; + atpdev->dev_id = ent->device; host_id &= 0x07; - atp_dev.host_id[0] = host_id; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x0b; - atp_dev.global_map[0] = inb(tmport++); - atp_dev.ultra_map[0] = inw(tmport); + atpdev->global_map[0] = inb(tmport++); + atpdev->ultra_map[0] = inw(tmport); - if (atp_dev.ultra_map[0] == 0) { - atp_dev.scam_on = 0x00; - atp_dev.global_map[0] = 0x20; - atp_dev.ultra_map[0] = 0xffff; + if (atpdev->ultra_map[0] == 0) { + atpdev->scam_on = 0x00; + atpdev->global_map[0] = 0x20; + atpdev->ultra_map[0] = 0xffff; } shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -3010,7 +3013,7 @@ flash_ok_885: } spin_lock_irqsave(shpnt->host_lock, flags); - if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ + if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ tmport = base_io + 0x3e; outb(0x00, tmport); } @@ -3044,7 +3047,7 @@ flash_ok_885: outb((inb(tmport) & 0xef), tmport); tmport++; outb((inb(tmport) | 0x20), tmport); - if (atp_dev.chip_ver == 4) + if (atpdev->chip_ver == 4) shpnt->max_id = 16; else shpnt->max_id = 8; @@ -3093,6 +3096,12 @@ unregister: printk("atp870u_prob:unregister\n"); scsi_host_put(shpnt); return -1; +err_eio: + kfree(atpdev); + return -EIO; +err_nomem: + kfree(atpdev); + return -ENOMEM; } /* The abort command does not leave the device in a clean state where diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 944fc1203eb..669ea4fff16 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -535,6 +535,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, struct ibmvscsi_host_data *hostdata) { u64 *crq_as_u64 = (u64 *) &evt_struct->crq; + int request_status; int rc; /* If we have exhausted our request limit, just fail this request. @@ -542,9 +543,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, * (such as task management requests) that the mid layer may think we * can handle more requests (can_queue) when we actually can't */ - if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && - (atomic_dec_if_positive(&hostdata->request_limit) < 0)) - goto send_error; + if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) { + request_status = + atomic_dec_if_positive(&hostdata->request_limit); + /* If request limit was -1 when we started, it is now even + * less than that + */ + if (request_status < -1) + goto send_error; + /* Otherwise, if we have run out of requests */ + else if (request_status < 0) + goto send_busy; + } /* Copy the IU into the transfer area */ *evt_struct->xfer_iu = evt_struct->iu; @@ -567,11 +577,23 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, return 0; - send_error: + send_busy: unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; + + send_error: + unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); + + if (evt_struct->cmnd != NULL) { + evt_struct->cmnd->result = DID_ERROR << 16; + evt_struct->cmnd_done(evt_struct->cmnd); + } else if (evt_struct->done) + evt_struct->done(evt_struct); + + free_event_struct(&hostdata->pool, evt_struct); + return 0; } /** @@ -1184,27 +1206,37 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, return; case 0xFF: /* Hypervisor telling us the connection is closed */ scsi_block_requests(hostdata->host); + atomic_set(&hostdata->request_limit, 0); if (crq->format == 0x06) { /* We need to re-setup the interpartition connection */ printk(KERN_INFO "ibmvscsi: Re-enabling adapter!\n"); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_REQUEUE); - if (ibmvscsi_reenable_crq_queue(&hostdata->queue, - hostdata) == 0) - if (ibmvscsi_send_crq(hostdata, - 0xC001000000000000LL, 0)) + if ((ibmvscsi_reenable_crq_queue(&hostdata->queue, + hostdata) == 0) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); printk(KERN_ERR - "ibmvscsi: transmit error after" + "ibmvscsi: error after" " enable\n"); + } } else { printk(KERN_INFO "ibmvscsi: Virtual adapter failed rc %d!\n", crq->format); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_ERROR); - ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + if ((ibmvscsi_reset_crq_queue(&hostdata->queue, + hostdata)) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); + printk(KERN_ERR + "ibmvscsi: error after reset\n"); + } } scsi_unblock_requests(hostdata->host); return; @@ -1467,6 +1499,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct Scsi_Host *host; struct device *dev = &vdev->dev; unsigned long wait_switch = 0; + int rc; vdev->dev.driver_data = NULL; @@ -1484,8 +1517,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */ - if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, - max_requests) != 0) { + rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests); + if (rc != 0 && rc != H_RESOURCE) { printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); goto init_crq_failed; } @@ -1505,7 +1538,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) * to fail if the other end is not acive. In that case we don't * want to scan */ - if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { + if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0 + || rc == H_RESOURCE) { /* * Wait around max init_timeout secs for the adapter to finish * initializing. When we are done initializing, we will have a diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 1a9992bdfef..242b8873b33 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -208,6 +208,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, int max_requests) { int rc; + int retrc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); @@ -226,7 +227,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, gather_partition_info(); set_adapter_info(hostdata); - rc = plpar_hcall_norets(H_REG_CRQ, + retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) @@ -263,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, (unsigned long)hostdata); - return 0; + return retrc; req_irq_failed: do { diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b4743a9ecc8..848fb2aa4ca 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2130,19 +2130,21 @@ iscsi_r2tpool_free(struct iscsi_session *session) static int iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, - uint32_t value) + char *buf, int buflen) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int value; switch(param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: { char *saveptr = tcp_conn->data; gfp_t flags = GFP_KERNEL; + sscanf(buf, "%d", &value); if (tcp_conn->data_size >= value) { - conn->max_recv_dlength = value; + iscsi_set_param(cls_conn, param, buf, buflen); break; } @@ -2165,15 +2167,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, else free_pages((unsigned long)saveptr, get_order(tcp_conn->data_size)); - conn->max_recv_dlength = value; + iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->data_size = value; - } - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - conn->max_xmit_dlength = value; break; + } case ISCSI_PARAM_HDRDGST_EN: - conn->hdrdgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->hdr_size = sizeof(struct iscsi_hdr); if (conn->hdrdgst_en) { tcp_conn->hdr_size += sizeof(__u32); @@ -2197,7 +2196,7 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, } break; case ISCSI_PARAM_DATADGST_EN: - conn->datadgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (conn->datadgst_en) { if (!tcp_conn->data_tx_tfm) tcp_conn->data_tx_tfm = @@ -2220,121 +2219,36 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, tcp_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_conn->sock->ops->sendpage; break; - case ISCSI_PARAM_INITIAL_R2T_EN: - session->initial_r2t_en = value; - break; case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &value); if (session->max_r2t == roundup_pow_of_two(value)) break; iscsi_r2tpool_free(session); - session->max_r2t = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (session->max_r2t & (session->max_r2t - 1)) session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; - case ISCSI_PARAM_IMM_DATA_EN: - session->imm_data_en = value; - break; - case ISCSI_PARAM_FIRST_BURST: - session->first_burst = value; - break; - case ISCSI_PARAM_MAX_BURST: - session->max_burst = value; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - session->pdu_inorder_en = value; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - session->dataseq_inorder_en = value; - break; - case ISCSI_PARAM_ERL: - session->erl = value; - break; - case ISCSI_PARAM_IFMARKER_EN: - BUG_ON(value); - session->ifmarker_en = value; - break; - case ISCSI_PARAM_OFMARKER_EN: - BUG_ON(value); - session->ofmarker_en = value; - break; - case ISCSI_PARAM_EXP_STATSN: - conn->exp_statsn = value; - break; - default: - break; - } - - return 0; -} - -static int -iscsi_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, uint32_t *value) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct iscsi_session *session = iscsi_hostdata(shost->hostdata); - - switch(param) { - case ISCSI_PARAM_INITIAL_R2T_EN: - *value = session->initial_r2t_en; - break; - case ISCSI_PARAM_MAX_R2T: - *value = session->max_r2t; - break; - case ISCSI_PARAM_IMM_DATA_EN: - *value = session->imm_data_en; - break; - case ISCSI_PARAM_FIRST_BURST: - *value = session->first_burst; - break; - case ISCSI_PARAM_MAX_BURST: - *value = session->max_burst; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - *value = session->pdu_inorder_en; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - *value = session->dataseq_inorder_en; - break; - case ISCSI_PARAM_ERL: - *value = session->erl; - break; - case ISCSI_PARAM_IFMARKER_EN: - *value = session->ifmarker_en; - break; - case ISCSI_PARAM_OFMARKER_EN: - *value = session->ofmarker_en; - break; default: - return -EINVAL; + return iscsi_set_param(cls_conn, param, buf, buflen); } return 0; } static int -iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t *value) +iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct inet_sock *inet; + struct ipv6_pinfo *np; + struct sock *sk; + int len; switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = conn->hdrdgst_en; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = conn->datadgst_en; - break; case ISCSI_PARAM_CONN_PORT: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2343,30 +2257,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, } inet = inet_sk(tcp_conn->sock->sk); - *value = be16_to_cpu(inet->dport); + len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); mutex_unlock(&conn->xmitmutex); - case ISCSI_PARAM_EXP_STATSN: - *value = conn->exp_statsn; break; - default: - return -EINVAL; - } - - return 0; -} - -static int -iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct sock *sk; - struct inet_sock *inet; - struct ipv6_pinfo *np; - int len = 0; - - switch (param) { case ISCSI_PARAM_CONN_ADDRESS: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2388,7 +2281,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, mutex_unlock(&conn->xmitmutex); break; default: - return -EINVAL; + return iscsi_conn_get_param(cls_conn, param, buf); } return len; @@ -2501,7 +2394,11 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_ERL | ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | - ISCSI_EXP_STATSN, + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, @@ -2514,8 +2411,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .bind_conn = iscsi_tcp_conn_bind, .destroy_conn = iscsi_tcp_conn_destroy, .set_param = iscsi_conn_set_param, - .get_conn_param = iscsi_conn_get_param, - .get_conn_str_param = iscsi_conn_get_str_param, + .get_conn_param = iscsi_tcp_conn_get_param, .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, .stop_conn = iscsi_conn_stop, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2673a11a949..7e6e031cc41 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1287,13 +1287,18 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (scsi_add_host(shost, NULL)) goto add_host_fail; + if (!try_module_get(iscsit->owner)) + goto cls_session_fail; + cls_session = iscsi_create_session(shost, iscsit, 0); if (!cls_session) - goto cls_session_fail; + goto module_put; *(unsigned long*)shost->hostdata = (unsigned long)cls_session; return cls_session; +module_put: + module_put(iscsit->owner); cls_session_fail: scsi_remove_host(shost); add_host_fail: @@ -1325,6 +1330,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) iscsi_destroy_session(cls_session); scsi_host_put(shost); + module_put(cls_session->transport->owner); } EXPORT_SYMBOL_GPL(iscsi_session_teardown); @@ -1697,6 +1703,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, } EXPORT_SYMBOL_GPL(iscsi_conn_bind); + +int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + uint32_t value; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + sscanf(buf, "%d", &conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + sscanf(buf, "%d", &conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + sscanf(buf, "%d", &conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + sscanf(buf, "%d", &conn->datadgst_en); + break; + case ISCSI_PARAM_INITIAL_R2T_EN: + sscanf(buf, "%d", &session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + sscanf(buf, "%d", &session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + sscanf(buf, "%d", &session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + sscanf(buf, "%d", &session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + sscanf(buf, "%d", &session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + sscanf(buf, "%d", &session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + sscanf(buf, "%d", &session->erl); + break; + case ISCSI_PARAM_IFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_OFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_EXP_STATSN: + sscanf(buf, "%u", &conn->exp_statsn); + break; + case ISCSI_PARAM_TARGET_NAME: + /* this should not change between logins */ + if (session->targetname) + break; + + session->targetname = kstrdup(buf, GFP_KERNEL); + if (!session->targetname) + return -ENOMEM; + break; + case ISCSI_PARAM_TPGT: + sscanf(buf, "%d", &session->tpgt); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + sscanf(buf, "%d", &conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + /* + * this is the address returned in discovery so it should + * not change between logins. + */ + if (conn->persistent_address) + break; + + conn->persistent_address = kstrdup(buf, GFP_KERNEL); + if (!conn->persistent_address) + return -ENOMEM; + break; + default: + return -ENOSYS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_set_param); + +int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + enum iscsi_param param, char *buf) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + int len; + + switch(param) { + case ISCSI_PARAM_INITIAL_R2T_EN: + len = sprintf(buf, "%d\n", session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + len = sprintf(buf, "%hu\n", session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + len = sprintf(buf, "%d\n", session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + len = sprintf(buf, "%u\n", session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + len = sprintf(buf, "%u\n", session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + len = sprintf(buf, "%d\n", session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + len = sprintf(buf, "%d\n", session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + len = sprintf(buf, "%d\n", session->erl); + break; + case ISCSI_PARAM_TARGET_NAME: + len = sprintf(buf, "%s\n", session->targetname); + break; + case ISCSI_PARAM_TPGT: + len = sprintf(buf, "%d\n", session->tpgt); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_session_get_param); + +int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + int len; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + len = sprintf(buf, "%d\n", conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + len = sprintf(buf, "%d\n", conn->datadgst_en); + break; + case ISCSI_PARAM_IFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ifmarker_en); + break; + case ISCSI_PARAM_OFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ofmarker_en); + break; + case ISCSI_PARAM_EXP_STATSN: + len = sprintf(buf, "%u\n", conn->exp_statsn); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + len = sprintf(buf, "%d\n", conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + len = sprintf(buf, "%s\n", conn->persistent_address); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_conn_get_param); + MODULE_AUTHOR("Mike Christie"); MODULE_DESCRIPTION("iSCSI library functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 087c44539a1..f81691fcf17 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -174,7 +174,6 @@ struct lpfc_hba { dma_addr_t slim2p_mapping; uint16_t pci_cfg_value; - struct semaphore hba_can_block; int32_t hba_state; #define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 283b7d824c3..4126fd87956 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -821,7 +821,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry) pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did, + elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -2791,8 +2791,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp = (struct lpfc_nodelist *) pmb->context2; xri = (uint16_t) ((unsigned long)(pmb->context1)); - pmb->context1 = 0; - pmb->context2 = 0; + pmb->context1 = NULL; + pmb->context2 = NULL; if (mb->mbxStatus) { mempool_free( pmb, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5a28d9bf8e4..81755a3f7c6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -939,12 +939,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) "10-port ", "PCIe"}; break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } @@ -1451,7 +1451,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_put_host; host->unique_id = phba->brd_no; - init_MUTEX(&phba->hba_can_block); INIT_LIST_HEAD(&phba->ctrspbuflist); INIT_LIST_HEAD(&phba->rnidrspbuflist); INIT_LIST_HEAD(&phba->freebufList); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7dc4c2e6bed..aea1ee472f3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -41,20 +41,6 @@ #define LPFC_ABORT_WAIT 2 -static inline void -lpfc_block_requests(struct lpfc_hba * phba) -{ - down(&phba->hba_can_block); - scsi_block_requests(phba->host); -} - -static inline void -lpfc_unblock_requests(struct lpfc_hba * phba) -{ - scsi_unblock_requests(phba->host); - up(&phba->hba_can_block); -} - /* * This routine allocates a scsi buffer, which contains all the necessary * information needed to initiate a SCSI I/O. The non-DMAable buffer region @@ -859,7 +845,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) unsigned int loop_count = 0; int ret = SUCCESS; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -945,7 +930,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) cmnd->device->lun, cmnd->serial_number); spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -963,7 +947,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) int ret = FAILED; int cnt, loopcnt; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); /* * If target is not in a MAPPED state, delay the reset until @@ -1065,7 +1048,6 @@ out_free_scsi_buf: out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -1080,7 +1062,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int cnt, loopcnt; struct lpfc_scsi_buf * lpfc_cmd; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); lpfc_cmd = lpfc_get_scsi_buf(phba); @@ -1163,7 +1144,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) phba->brd_no, ret); out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e5c017ccda5..a8c9627a15c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.02.04 + * Version : v00.00.03.01 * * Authors: * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com> @@ -55,19 +55,25 @@ static struct pci_device_id megasas_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP + PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1078R, // ppc IOP + PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */ PCI_ANY_ID, PCI_ANY_ID, }, { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_LSI_VERDE_ZCR, /* xscale IOP, vega */ + PCI_ANY_ID, + PCI_ANY_ID, + }, + { PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_DELL_PERC5, // xscale IOP + PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, @@ -289,9 +295,14 @@ static struct megasas_instance_template megasas_instance_template_ppc = { * @regs: MFI register set */ static inline void -megasas_disable_intr(struct megasas_register_set __iomem * regs) +megasas_disable_intr(struct megasas_instance *instance) { u32 mask = 0x1f; + struct megasas_register_set __iomem *regs = instance->reg_set; + + if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R) + mask = 0xffffffff; + writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -1260,7 +1271,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) /* * Bring it to READY state; assuming max wait 2 secs */ - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell); max_wait = 10; @@ -1757,6 +1768,11 @@ static int megasas_init_mfi(struct megasas_instance *instance) init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); /* + * disable the intr before firing the init frame to FW + */ + megasas_disable_intr(instance); + + /* * Issue the init frame in polled mode */ if (megasas_issue_polled(instance, cmd)) { @@ -2234,7 +2250,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) megasas_mgmt_info.max_index--; pci_set_drvdata(pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); megasas_release_mfi(instance); @@ -2364,7 +2380,7 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_set_drvdata(instance->pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 927d6ffef05..3531a14222a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,16 @@ /** * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.02.04" -#define MEGASAS_RELDATE "Feb 03, 2006" -#define MEGASAS_EXT_VERSION "Fri Feb 03 14:31:44 PST 2006" +#define MEGASAS_VERSION "00.00.03.01" +#define MEGASAS_RELDATE "May 14, 2006" +#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006" + +/* + * Device IDs + */ +#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060 +#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413 + /* * ===================================== * MegaRAID SAS MFI firmware definitions @@ -554,7 +561,11 @@ struct megasas_ctrl_info { #define MFI_POLL_TIMEOUT_SECS 10 #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 -#define PCI_DEVICE_ID_LSI_SAS1078R 0x00000060 + +/* +* register set for both 1068 and 1078 controllers +* structure extended for 1078 registers +*/ struct megasas_register_set { u32 reserved_0[4]; /*0000h*/ @@ -1150,10 +1161,10 @@ struct compat_megasas_iocpacket { struct compat_iovec sgl[MAX_IOCTL_SGE]; } __attribute__ ((packed)); +#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #endif #define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) -#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) struct megasas_mgmt_info { diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index bd337a91429..bfb4f49e125 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -2866,8 +2866,7 @@ static int nsp32_detect(struct scsi_host_template *sht) */ nsp32_do_bus_reset(data); - ret = request_irq(host->irq, do_nsp32_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "nsp32", data); + ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data); if (ret < 0) { nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 " "SCSI PCI controller. Interrupt: %d", host->irq); @@ -2886,12 +2885,19 @@ static int nsp32_detect(struct scsi_host_template *sht) } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - scsi_add_host (host, &PCIDEV->dev); + ret = scsi_add_host(host, &PCIDEV->dev); + if (ret) { + nsp32_msg(KERN_ERR, "failed to add scsi host"); + goto free_region; + } scsi_scan_host(host); #endif pci_set_drvdata(PCIDEV, host); return DETECT_OK; + free_region: + release_region(host->io_port, host->n_io_port); + free_irq: free_irq(host->irq, data); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 7ff5851c040..0d4c04e1f3d 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1623,7 +1623,7 @@ static int nsp_cs_probe(struct pcmcia_device *link) /* Interrupt handler */ link->irq.Handler = &nspintr; link->irq.Instance = info; - link->irq.Attributes |= (IRQF_SHARED | IRQF_SAMPLE_RANDOM); + link->irq.Attributes |= IRQF_SHARED; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index b818b9bfe67..8953991462d 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4209,7 +4209,7 @@ qla1280_setup(char *s) } -static int +static int __init qla1280_get_token(char *str) { char *sep; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e96d58ded57..87f90c4f08e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off, { struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); + char *rbuf = (char *)ha->fw_dump; if (ha->fw_dump_reading == 0) return 0; - if (off > ha->fw_dump_buffer_len) - return 0; - if (off + count > ha->fw_dump_buffer_len) - count = ha->fw_dump_buffer_len - off; + if (off > ha->fw_dump_len) + return 0; + if (off + count > ha->fw_dump_len) + count = ha->fw_dump_len - off; - memcpy(buf, &ha->fw_dump_buffer[off], count); + memcpy(buf, &rbuf[off], count); return (count); } @@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); int reading; - uint32_t dump_size; if (off != 0) return (0); @@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, reading = simple_strtol(buf, NULL, 10); switch (reading) { case 0: - if (ha->fw_dump_reading == 1) { - qla_printk(KERN_INFO, ha, - "Firmware dump cleared on (%ld).\n", ha->host_no); + if (!ha->fw_dump_reading) + break; - vfree(ha->fw_dump_buffer); - ha->fw_dump_buffer = NULL; - ha->fw_dump_reading = 0; - ha->fw_dumped = 0; - } + qla_printk(KERN_INFO, ha, + "Firmware dump cleared on (%ld).\n", ha->host_no); + + ha->fw_dump_reading = 0; + ha->fw_dumped = 0; break; case 1: if (ha->fw_dumped && !ha->fw_dump_reading) { ha->fw_dump_reading = 1; - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) - dump_size = FW_DUMP_SIZE_24XX; - else { - dump_size = FW_DUMP_SIZE_1M; - if (ha->fw_memory_size < 0x20000) - dump_size = FW_DUMP_SIZE_128K; - else if (ha->fw_memory_size < 0x80000) - dump_size = FW_DUMP_SIZE_512K; - } - ha->fw_dump_buffer = (char *)vmalloc(dump_size); - if (ha->fw_dump_buffer == NULL) { - qla_printk(KERN_WARNING, ha, - "Unable to allocate memory for firmware " - "dump buffer (%d).\n", dump_size); - - ha->fw_dump_reading = 0; - return (count); - } qla_printk(KERN_INFO, ha, - "Firmware dump ready for read on (%ld).\n", + "Raw firmware dump ready for read on (%ld).\n", ha->host_no); - memset(ha->fw_dump_buffer, 0, dump_size); - ha->isp_ops.ascii_fw_dump(ha); - ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer); } break; + case 2: + qla2x00_alloc_fw_dump(ha); + break; } return (count); } @@ -313,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Read NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size); @@ -335,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Write NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count); @@ -357,6 +332,53 @@ static struct bin_attribute sysfs_vpd_attr = { .write = qla2x00_sysfs_write_vpd, }; +static ssize_t +qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + uint16_t iter, addr, offset; + int rval; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) + return 0; + + addr = 0xa0; + for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; + iter++, offset += SFP_BLOCK_SIZE) { + if (iter == 4) { + /* Skip to next device address. */ + addr = 0xa2; + offset = 0; + } + + rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset, + SFP_BLOCK_SIZE); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to read SFP data (%x/%x/%x).\n", rval, + addr, offset); + count = 0; + break; + } + memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE); + buf += SFP_BLOCK_SIZE; + } + + return count; +} + +static struct bin_attribute sysfs_sfp_attr = { + .attr = { + .name = "sfp", + .mode = S_IRUSR | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = SFP_DEV_SIZE * 2, + .read = qla2x00_sysfs_read_sfp, +}; + void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) { @@ -367,7 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); + } } void @@ -380,7 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); + } if (ha->beacon_blink_led == 1) ha->isp_ops.beacon_off(ha); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 74e54713aa7..f6ed6962bc2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -8,7 +8,34 @@ #include <linux/delay.h> -static int qla_uprintf(char **, char *, ...); +static inline void +qla2xxx_prep_dump(scsi_qla_host_t *ha, struct qla2xxx_fw_dump *fw_dump) +{ + fw_dump->fw_major_version = htonl(ha->fw_major_version); + fw_dump->fw_minor_version = htonl(ha->fw_minor_version); + fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version); + fw_dump->fw_attributes = htonl(ha->fw_attributes); + + fw_dump->vendor = htonl(ha->pdev->vendor); + fw_dump->device = htonl(ha->pdev->device); + fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor); + fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device); +} + +static inline void * +qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr) +{ + /* Request queue. */ + memcpy(ptr, ha->request_ring, ha->request_q_length * + sizeof(request_t)); + + /* Response queue. */ + ptr += ha->request_q_length * sizeof(request_t); + memcpy(ptr, ha->response_ring, ha->response_q_length * + sizeof(response_t)); + + return ptr + (ha->response_q_length * sizeof(response_t)); +} /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. @@ -49,10 +76,11 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2300_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp23; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -73,85 +101,86 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) - fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x40); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) - fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x50); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2800); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2A00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2C00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2E00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -226,7 +255,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -285,7 +314,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->stack_ram[cnt] = mb2; + fw->stack_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -345,12 +374,15 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->data_ram[cnt] = mb2; + fw->data_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->data_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -369,193 +401,6 @@ qla2300_fw_dump_failed: } /** - * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2300_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2300_fw_dump *fw; - uint32_t data_ram_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nStack RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000); - } - qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nData RAM Dump:"); - data_ram_cnt = ha->fw_memory_size - 0x11000 + 1; - for (cnt = 0; cnt < data_ram_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000); - } - qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); -} - -/** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. * @ha: HA context * @hardware_locked: Called with the hardware_lock @@ -591,10 +436,11 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2100_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp21; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -608,79 +454,81 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < ha->mbx_count; cnt++) { if (cnt == 8) { - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0); + dmp_reg = (uint16_t __iomem *) + ((uint8_t __iomem *)reg + 0xe0); } - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); } dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2100); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2300); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2500); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2700); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -755,12 +603,15 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -778,179 +629,6 @@ qla2100_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -/** - * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2100_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2100_fw_dump *fw; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC SRAM:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); - - return; -} - -static int -qla_uprintf(char **uiter, char *fmt, ...) -{ - int iter, len; - char buf[128]; - va_list args; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - for (iter = 0; iter < len; iter++, *uiter += 1) - *uiter[0] = buf[iter]; - - return (len); -} - - void qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { @@ -967,6 +645,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) unsigned long flags; struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; + void *eft; risc_address = ext_mem_cnt = 0; memset(mb, 0, sizeof(mb)); @@ -987,10 +666,11 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla24xx_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp24; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->host_status = RD_REG_DWORD(®->host_status); + fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ if ((RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0) { @@ -1012,7 +692,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) /* Host interface registers. */ dmp_reg = (uint32_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Disable interrupts. */ WRT_REG_DWORD(®->ictrl, 0); @@ -1024,470 +704,471 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0000000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0100000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0200000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0300000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0400000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0500000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0600000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg)); /* Mailbox registers. */ mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(mbx_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); /* Transfer sequence registers. */ iter_reg = fw->xseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xBF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) - fw->xseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) - fw->xseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Receive sequence registers. */ iter_reg = fw->rseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xFF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFD0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) - fw->rseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) - fw->rseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) - fw->rseq_2_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Command DMA registers. */ WRT_REG_DWORD(®->iobase_addr, 0x7100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) - fw->cmd_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Queues. */ iter_reg = fw->req0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7200); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->resp0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7300); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->req1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7400); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Transmit DMA registers. */ iter_reg = fw->xmt0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7600); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7610); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7620); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7630); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt2_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7640); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7650); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt3_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7660); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7670); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt4_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7680); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7690); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x76A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) - fw->xmt_data_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xmt_data_dma_reg[cnt] = + htonl(RD_REG_DWORD(dmp_reg++)); /* Receive DMA registers. */ iter_reg = fw->rcvt0_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7700); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7710); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->rcvt1_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7720); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7730); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* RISC registers. */ iter_reg = fw->risc_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0x0F00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Local memory controller registers. */ iter_reg = fw->lmc_reg; WRT_REG_DWORD(®->iobase_addr, 0x3000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Fibre Protocol Module registers. */ iter_reg = fw->fpm_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x4000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4070); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4080); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4090); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Frame Buffer registers. */ iter_reg = fw->fb_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x6000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6130); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6150); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6170); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6190); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x61B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, @@ -1577,7 +1258,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->code_ram[cnt] = (mb[3] << 16) | mb[2]; + fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } @@ -1627,12 +1308,18 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->ext_mem[cnt] = (mb[3] << 16) | mb[2]; + fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) { + eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]); + if (ha->eft) + memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size)); + } + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -1650,252 +1337,6 @@ qla24xx_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -void -qla24xx_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - struct qla24xx_fw_dump *fw; - uint32_t ext_mem_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "ISP FW Version %d.%02d.%02d Attributes %04x\n", - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, ha->fw_attributes); - - qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status); - - qla_uprintf(&uiter, "\nHost Interface Registers"); - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nShadow Registers"); - for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers"); - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-2 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCommand DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->cmd_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nResponse0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->resp0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->resp0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest1 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT2 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt2_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt2_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT3 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt3_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt3_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT4 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt4_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt4_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT Data DMA Common Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt0_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt0_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt1_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt1_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP Registers"); - for (cnt = 0; cnt < sizeof(fw->risc_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nLMC Registers"); - for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->lmc_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fpm_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fpm_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFB Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fb_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fb_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM"); - for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x20000); - } - qla_uprintf(&uiter, "%08x ", fw->code_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nExternal Memory"); - ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1; - for (cnt = 0; cnt < ext_mem_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x100000); - } - qla_uprintf(&uiter, "%08x ", fw->ext_mem[cnt]); - } - - qla_uprintf(&uiter, "\n[<==END] ISP Debug Dump"); -} - - /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index ab6afeaa2f2..533425338e0 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -37,134 +37,86 @@ /* * Macros use for debugging the driver. */ -#undef ENTER_TRACE -#if defined(ENTER_TRACE) -#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#else -#define ENTER(x) do {} while (0) -#define LEAVE(x) do {} while (0) -#define ENTER_INTR(x) do {} while (0) -#define LEAVE_INTR(x) do {} while (0) -#endif -#if DEBUG_QLA2100 -#define DEBUG(x) do {x;} while (0); -#else -#define DEBUG(x) do {} while (0); -#endif +#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) -#define DEBUG1(x) do {x;} while (0); +#define DEBUG1(x) do {x;} while (0) #else -#define DEBUG1(x) do {} while (0); +#define DEBUG1(x) do {} while (0) #endif -#if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG2_11(x) do {x;} while (0); -#define DEBUG2_13(x) do {x;} while (0); -#else -#define DEBUG2(x) do {} while (0); -#endif +#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG3_11(x) do {x;} while (0); +#define DEBUG3(x) do {x;} while (0) +#define DEBUG3_11(x) do {x;} while (0) #else -#define DEBUG3(x) do {} while (0); - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_3(x) do {} while (0); - #endif +#define DEBUG3(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_4) -#define DEBUG4(x) do {x;} while (0); +#define DEBUG4(x) do {x;} while (0) #else -#define DEBUG4(x) do {} while (0); +#define DEBUG4(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_5) -#define DEBUG5(x) do {x;} while (0); +#define DEBUG5(x) do {x;} while (0) #else -#define DEBUG5(x) do {} while (0); +#define DEBUG5(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_7) -#define DEBUG7(x) do {x;} while (0); +#define DEBUG7(x) do {x;} while (0) #else -#define DEBUG7(x) do {} while (0); +#define DEBUG7(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_9) -#define DEBUG9(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); +#define DEBUG9(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) #else -#define DEBUG9(x) do {} while (0); +#define DEBUG9(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_10) -#define DEBUG10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); +#define DEBUG10(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) #else -#define DEBUG10(x) do {} while (0); - #if !defined(DEBUG2_9_10) - #define DEBUG2_9_10(x) do {} while (0); - #endif +#define DEBUG10(x) do {} while (0) #if !defined(DEBUG9_10) - #define DEBUG9_10(x) do {} while (0); + #define DEBUG9_10(x) do {} while (0) #endif #endif #if defined(QL_DEBUG_LEVEL_11) -#define DEBUG11(x) do{x;} while(0); -#if !defined(DEBUG2_11) -#define DEBUG2_11(x) do{x;} while(0); -#endif -#if !defined(DEBUG2_3_11) -#define DEBUG2_3_11(x) do{x;} while(0); -#endif +#define DEBUG11(x) do{x;} while(0) #if !defined(DEBUG3_11) -#define DEBUG3_11(x) do{x;} while(0); +#define DEBUG3_11(x) do{x;} while(0) #endif #else -#define DEBUG11(x) do{} while(0); - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_11(x) do{} while(0); - #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG2_3_11(x) do{} while(0); - #endif - #endif +#define DEBUG11(x) do{} while(0) #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG3_11(x) do{} while(0); + #define DEBUG3_11(x) do{} while(0) #endif #endif #if defined(QL_DEBUG_LEVEL_12) -#define DEBUG12(x) do {x;} while (0); +#define DEBUG12(x) do {x;} while (0) #else -#define DEBUG12(x) do {} while (0); +#define DEBUG12(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_13) #define DEBUG13(x) do {x;} while (0) -#if !defined(DEBUG2_13) -#define DEBUG2_13(x) do {x;} while(0) -#endif #else #define DEBUG13(x) do {} while (0) -#if !defined(QL_DEBUG_LEVEL_2) -#define DEBUG2_13(x) do {} while(0) -#endif #endif #if defined(QL_DEBUG_LEVEL_14) @@ -176,9 +128,6 @@ /* * Firmware Dump structure definition */ -#define FW_DUMP_SIZE_128K 0xBC000 -#define FW_DUMP_SIZE_512K 0x2FC000 -#define FW_DUMP_SIZE_1M 0x5FC000 struct qla2300_fw_dump { uint16_t hccr; @@ -224,8 +173,6 @@ struct qla2100_fw_dump { uint16_t risc_ram[0xf000]; }; -#define FW_DUMP_SIZE_24XX 0x2B0000 - struct qla24xx_fw_dump { uint32_t host_status; uint32_t host_reg[32]; @@ -257,3 +204,39 @@ struct qla24xx_fw_dump { uint32_t code_ram[0x2000]; uint32_t ext_mem[1]; }; + +#define EFT_NUM_BUFFERS 4 +#define EFT_BYTES_PER_BUFFER 0x4000 +#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) + +struct qla2xxx_fw_dump { + uint8_t signature[4]; + uint32_t version; + + uint32_t fw_major_version; + uint32_t fw_minor_version; + uint32_t fw_subminor_version; + uint32_t fw_attributes; + + uint32_t vendor; + uint32_t device; + uint32_t subsystem_vendor; + uint32_t subsystem_device; + + uint32_t fixed_size; + uint32_t mem_size; + uint32_t req_q_size; + uint32_t rsp_q_size; + + uint32_t eft_size; + uint32_t eft_addr_l; + uint32_t eft_addr_h; + + uint32_t header_size; + + union { + struct qla2100_fw_dump isp21; + struct qla2300_fw_dump isp23; + struct qla24xx_fw_dump isp24; + } isp; +}; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6734453ea28..139ea0e27fd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -608,7 +608,9 @@ typedef struct { #define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */ #define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */ #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ +#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ +#define MBC_READ_SFP 0x31 /* Read SFP Data. */ #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ #define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */ @@ -618,6 +620,9 @@ typedef struct { #define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ #define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ +#define TC_ENABLE 4 +#define TC_DISABLE 5 + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -1997,7 +2002,6 @@ struct isp_operations { uint32_t); void (*fw_dump) (struct scsi_qla_host *, int); - void (*ascii_fw_dump) (struct scsi_qla_host *); int (*beacon_on) (struct scsi_qla_host *); int (*beacon_off) (struct scsi_qla_host *); @@ -2041,6 +2045,7 @@ typedef struct scsi_qla_host { uint32_t enable_led_scheme :1; uint32_t msi_enabled :1; uint32_t msix_enabled :1; + uint32_t disable_serdes :1; } flags; atomic_t loop_state; @@ -2238,6 +2243,11 @@ typedef struct scsi_qla_host { struct sns_cmd_pkt *sns_cmd; dma_addr_t sns_cmd_dma; +#define SFP_DEV_SIZE 256 +#define SFP_BLOCK_SIZE 64 + void *sfp_data; + dma_addr_t sfp_data_dma; + struct task_struct *dpc_thread; uint8_t dpc_active; /* DPC routine is active */ @@ -2303,11 +2313,12 @@ typedef struct scsi_qla_host { uint16_t fw_seriallink_options24[4]; /* Firmware dump information. */ - void *fw_dump; + struct qla2xxx_fw_dump *fw_dump; + uint32_t fw_dump_len; int fw_dumped; int fw_dump_reading; - char *fw_dump_buffer; - int fw_dump_buffer_len; + dma_addr_t eft_dma; + void *eft; uint8_t host_str[16]; uint32_t pci_attr; diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h index a8fc0ffc7fc..dd435410dfa 100644 --- a/drivers/scsi/qla2xxx/qla_devtbl.h +++ b/drivers/scsi/qla2xxx/qla_devtbl.h @@ -1,4 +1,4 @@ -#define QLA_MODEL_NAMES 0x4A +#define QLA_MODEL_NAMES 0x57 /* * Adapter model names and descriptions. @@ -76,6 +76,19 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = { "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ - " ", " ", /* 0x148 */ + "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */ "QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */ + " ", " ", /* 0x14a */ + " ", " ", /* 0x14b */ + "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */ + "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */ + "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */ + " ", " ", /* 0x14f */ + " ", " ", /* 0x150 */ + " ", " ", /* 0x151 */ + "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */ + "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */ + " ", " ", /* 0x154 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */ }; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 3af478663be..a0a722cf423 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -141,7 +141,7 @@ struct nvram_24xx { * BIT 2 = Enable Memory Map BIOS * BIT 3 = Enable Selectable Boot * BIT 4 = Disable RISC code load - * BIT 5 = + * BIT 5 = Disable Serdes * BIT 6 = * BIT 7 = * @@ -278,7 +278,7 @@ struct init_cb_24xx { uint16_t response_q_length; uint16_t request_q_length; - uint16_t link_down_timeout; /* Milliseconds. */ + uint16_t link_down_on_nos; /* Milliseconds. */ uint16_t prio_request_q_length; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 164d53ccbfd..8311ac2b93a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -31,13 +31,9 @@ extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); - -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); -extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); @@ -51,6 +47,8 @@ extern int qla2x00_abort_isp(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); + /* * Global Data in qla_os.c source file. */ @@ -61,6 +59,8 @@ extern int qlport_down_retry; extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; +extern int ql2xallocfwdump; +extern int extended_error_logging; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -80,8 +80,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *); /* * Global Function Prototypes in qla_iocb.c source file. */ -extern void qla2x00_isp_cmd(scsi_qla_host_t *); - extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_64(uint16_t); extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); @@ -204,6 +202,12 @@ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); extern int qla2x00_stop_firmware(scsi_qla_host_t *); +extern int +qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); + +extern int +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -254,9 +258,6 @@ extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, extern void qla2100_fw_dump(scsi_qla_host_t *, int); extern void qla2300_fw_dump(scsi_qla_host_t *, int); extern void qla24xx_fw_dump(scsi_qla_host_t *, int); -extern void qla2100_ascii_fw_dump(scsi_qla_host_t *); -extern void qla2300_ascii_fw_dump(scsi_qla_host_t *); -extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); @@ -280,13 +281,6 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* - * Global Function Prototypes in qla_xioctl.c source file. - */ -#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0) -#define qla2x00_alloc_ioctl_mem(ha) (0) -#define qla2x00_free_ioctl_mem(ha) do { } while (0) - -/* * Global Function Prototypes in qla_attr.c source file. */ struct class_device_attribute; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3d4487eac9b..9758dba9554 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -39,6 +39,8 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, static int qla2x00_restart_isp(scsi_qla_host_t *); +static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -89,6 +91,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->isp_ops.nvram_config(ha); + if (ha->flags.disable_serdes) { + /* Mask HBA via NVRAM settings? */ + qla_printk(KERN_INFO, ha, "Masking HBA WWPN " + "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n", + ha->port_name[0], ha->port_name[1], + ha->port_name[2], ha->port_name[3], + ha->port_name[4], ha->port_name[5], + ha->port_name[6], ha->port_name[7]); + return QLA_FUNCTION_FAILED; + } + qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); retry = 10; @@ -770,29 +783,104 @@ qla24xx_chip_diag(scsi_qla_host_t *ha) return rval; } -static void +void qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) { - uint32_t dump_size = 0; + int rval; + uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, + eft_size; + dma_addr_t eft_dma; + void *eft; + + if (ha->fw_dump) { + qla_printk(KERN_WARNING, ha, + "Firmware dump previously allocated.\n"); + return; + } ha->fw_dumped = 0; + fixed_size = mem_size = eft_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - dump_size = sizeof(struct qla2100_fw_dump); + fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { - dump_size = sizeof(struct qla2300_fw_dump); - dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t); - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - dump_size = sizeof(struct qla24xx_fw_dump); - dump_size += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t); + fixed_size = offsetof(struct qla2300_fw_dump, data_ram); + mem_size = (ha->fw_memory_size - 0x11000 + 1) * + sizeof(uint16_t); + } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); + mem_size = (ha->fw_memory_size - 0x100000 + 1) * + sizeof(uint32_t); + + /* Allocate memory for Extended Trace Buffer. */ + eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma, + GFP_KERNEL); + if (!eft) { + qla_printk(KERN_WARNING, ha, "Unable to allocate " + "(%d KB) for EFT.\n", EFT_SIZE / 1024); + goto cont_alloc; + } + + rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma, + EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, "Unable to initialize " + "EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft, + eft_dma); + goto cont_alloc; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", + EFT_SIZE / 1024); + + eft_size = EFT_SIZE; + memset(eft, 0, eft_size); + ha->eft_dma = eft_dma; + ha->eft = eft; } +cont_alloc: + req_q_size = ha->request_q_length * sizeof(request_t); + rsp_q_size = ha->response_q_length * sizeof(response_t); + + dump_size = offsetof(struct qla2xxx_fw_dump, isp); + dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + + eft_size; ha->fw_dump = vmalloc(dump_size); - if (ha->fw_dump) - qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware " - "dump...\n", dump_size / 1024); - else + if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for " "firmware dump!!!\n", dump_size / 1024); + + if (ha->eft) { + dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft, + ha->eft_dma); + ha->eft = NULL; + ha->eft_dma = 0; + } + return; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n", + dump_size / 1024); + + ha->fw_dump_len = dump_size; + ha->fw_dump->signature[0] = 'Q'; + ha->fw_dump->signature[1] = 'L'; + ha->fw_dump->signature[2] = 'G'; + ha->fw_dump->signature[3] = 'C'; + ha->fw_dump->version = __constant_htonl(1); + + ha->fw_dump->fixed_size = htonl(fixed_size); + ha->fw_dump->mem_size = htonl(mem_size); + ha->fw_dump->req_q_size = htonl(req_q_size); + ha->fw_dump->rsp_q_size = htonl(rsp_q_size); + + ha->fw_dump->eft_size = htonl(eft_size); + ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); + ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); + + ha->fw_dump->header_size = + htonl(offsetof(struct qla2xxx_fw_dump, isp)); } /** @@ -810,8 +898,6 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) dma_addr_t request_dma; request_t *request_ring; - qla2x00_alloc_fw_dump(ha); - /* Valid only on recent ISPs. */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) return; @@ -883,6 +969,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); + + if (ql2xallocfwdump) + qla2x00_alloc_fw_dump(ha); } } else { DEBUG2(printk(KERN_INFO @@ -1186,8 +1275,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - (fw_state >= FSTATE_LOSS_OF_SYNC || - fw_state == FSTATE_WAIT_AL_PA)) { + fw_state != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ @@ -1555,6 +1643,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) /* * Set host adapter parameters. */ + if (nv->host_p[0] & BIT_7) + extended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) @@ -1563,6 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; + ha->flags.disable_serdes = 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -1701,7 +1792,7 @@ qla2x00_rport_del(void *data) * * Returns a pointer to the allocated fcport, or NULL, if none available. */ -fc_port_t * +static fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; @@ -2497,7 +2588,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) * Context: * Kernel context. */ -int +static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev) { int rval; @@ -3048,14 +3139,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt--; DEBUG(printk("qla%ld: ISP abort - " "retry remaining %d\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); status = 1; } } else { ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; DEBUG(printk("qla2x00(%ld): ISP error recovery " "- retrying (%d) more times\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); set_bit(ISP_ABORT_RETRY, &ha->dpc_flags); status = 1; } @@ -3069,7 +3160,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } else { DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): exiting.\n", - ha->host_no);) + ha->host_no)); } return(status); @@ -3145,7 +3236,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); if (!(status = qla2x00_fw_ready(ha))) { DEBUG(printk("%s(): Start configure loop, " - "status = %d\n", __func__, status);) + "status = %d\n", __func__, status)); /* Issue a marker after FW becomes ready. */ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); @@ -3169,7 +3260,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) DEBUG(printk("%s(): Configure loop done, status = 0x%x\n", __func__, - status);) + status)); } return (status); } @@ -3289,7 +3380,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) nv->node_name[6] = 0x55; nv->node_name[7] = 0x86; nv->login_retry_count = __constant_cpu_to_le16(8); - nv->link_down_timeout = __constant_cpu_to_le16(200); nv->interrupt_delay_timer = __constant_cpu_to_le16(0); nv->login_timeout = __constant_cpu_to_le16(0); nv->firmware_options_1 = @@ -3318,7 +3408,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) *dptr1++ = *dptr2++; icb->login_retry_count = nv->login_retry_count; - icb->link_down_timeout = nv->link_down_timeout; + icb->link_down_on_nos = nv->link_down_on_nos; /* Copy 2nd segment. */ dptr1 = (uint8_t *)&icb->interrupt_delay_timer; @@ -3373,6 +3463,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = 1; ha->flags.enable_target_reset = 1; ha->flags.enable_led_scheme = 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -3472,7 +3563,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) return (rval); } -int +static int qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr) { int rval; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8c769cfaa14..2b60a27eff0 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -15,6 +15,7 @@ static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); +static void qla2x00_isp_cmd(scsi_qla_host_t *ha); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. @@ -574,7 +575,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) * * Note: The caller must hold the hardware lock before calling this routine. */ -void +static void qla2x00_isp_cmd(scsi_qla_host_t *ha) { device_reg_t __iomem *reg = ha->iobase; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b28ac0a27e2..795bf15b1b8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -395,10 +395,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL); - break; case MBA_LOOP_UP: /* Loop Up Event */ @@ -418,9 +414,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) link_speed); ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL); break; case MBA_LOOP_DOWN: /* Loop Down Event */ @@ -439,9 +432,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->link_data_rate = LDR_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); break; case MBA_LIP_RESET: /* LIP reset occurred */ @@ -460,10 +450,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->operating_mode = LOOP; ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL); - break; case MBA_POINT_TO_POINT: /* Point-to-Point */ @@ -545,9 +531,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL); break; case MBA_RSCN_UPDATE: /* State Change Registration */ @@ -584,9 +567,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(RSCN_UPDATE, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]); break; /* case MBA_RIO_RESPONSE: */ @@ -1452,8 +1432,8 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", __func__, ha->host_no, pkt, pkt->handle)); - DEBUG9(printk("%s: ct pkt dump:\n", __func__);) - DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx));) + DEBUG9(printk("%s: ct pkt dump:\n", __func__)); + DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx))); /* Validate handle. */ if (pkt->handle < MAX_OUTSTANDING_COMMANDS) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d6cb3bd1a29..879f281e2ea 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -13,13 +13,13 @@ qla2x00_mbx_sem_timeout(unsigned long data) { struct semaphore *sem_ptr = (struct semaphore *)data; - DEBUG11(printk("qla2x00_sem_timeout: entered.\n");) + DEBUG11(printk("qla2x00_sem_timeout: entered.\n")); if (sem_ptr != NULL) { up(sem_ptr); } - DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");) + DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n")); } /* @@ -61,7 +61,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) rval = QLA_SUCCESS; abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); /* * Wait for active mailbox commands to finish by waiting at most tov @@ -72,7 +72,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) { /* Timeout occurred. Return error. */ DEBUG2_3_11(printk("%s(%ld): cmd access timeout. " - "Exiting.\n", __func__, ha->host_no);) + "Exiting.\n", __func__, ha->host_no)); return QLA_FUNCTION_TIMEOUT; } } @@ -86,7 +86,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -131,14 +131,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) /* Unlock mbx registers and wait for interrupt */ DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. " - "jiffies=%lx.\n", __func__, ha->host_no, jiffies);) + "jiffies=%lx.\n", __func__, ha->host_no, jiffies)); /* Wait for mbx cmd completion until timeout */ if (!abort_active && io_lock_on) { /* sleep on completion semaphore */ DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n", - __func__, ha->host_no);) + __func__, ha->host_no)); init_timer(&tmp_intr_timer); tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; @@ -147,11 +147,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) (void (*)(unsigned long))qla2x00_mbx_sem_timeout; DEBUG11(printk("%s(%ld): Adding timer.\n", __func__, - ha->host_no);) + ha->host_no)); add_timer(&tmp_intr_timer); DEBUG11(printk("%s(%ld): going to unlock & sleep. " - "time=0x%lx.\n", __func__, ha->host_no, jiffies);) + "time=0x%lx.\n", __func__, ha->host_no, jiffies)); set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); @@ -170,14 +170,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) down(&ha->mbx_intr_sem); DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__, - ha->host_no, jiffies);) + ha->host_no, jiffies)); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); /* delete the timer */ del_timer(&tmp_intr_timer); } else { DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); @@ -209,7 +209,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) uint16_t *iptr2; DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); /* Got interrupt. Clear the flag. */ ha->flags.mbox_int = 0; @@ -266,7 +266,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!abort_active) { DEBUG11(printk("%s(%ld): checking for additional resp " - "interrupt.\n", __func__, ha->host_no);) + "interrupt.\n", __func__, ha->host_no)); /* polling mode for non isp_abort commands. */ qla2x00_poll(ha); @@ -277,9 +277,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!io_lock_on || (mcp->flags & IOCTL_CMD)) { /* not in dpc. schedule it for dpc to take over. */ DEBUG(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Scheduling ISP " "abort.\n"); @@ -288,9 +288,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } else if (!abort_active) { /* call abort directly since we are in the DPC thread */ DEBUG(printk("%s(%ld): timeout calling abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout calling " - "abort_isp\n", __func__, ha->host_no);) + "abort_isp\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Issuing ISP " "abort.\n"); @@ -303,9 +303,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); DEBUG(printk("%s(%ld): finished abort_isp\n", __func__, - ha->host_no);) + ha->host_no)); DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); } } @@ -316,9 +316,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (rval) { DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, " "mbx2=%x, cmd=%x ****\n", __func__, ha->host_no, - mcp->mb[0], mcp->mb[1], mcp->mb[2], command);) + mcp->mb[0], mcp->mb[1], mcp->mb[2], command)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -394,7 +394,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; @@ -424,10 +424,10 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) } else { if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { DEBUG11(printk("%s(%ld): done exchanges=%x.\n", - __func__, ha->host_no, mcp->mb[1]);) + __func__, ha->host_no, mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, - ha->host_no);) + ha->host_no)); } } @@ -611,7 +611,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; mcp->mb[1] = 0xAAAA; @@ -639,11 +639,11 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -671,7 +671,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_VERIFY_CHECKSUM; mcp->out_mb = MBX_0; @@ -694,9 +694,9 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__, ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ? - (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));) + (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]))); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -743,9 +743,9 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sts_entry_t *sts_entry = (sts_entry_t *) buffer; @@ -781,7 +781,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no)); fcport = sp->fcport; @@ -813,11 +813,11 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sp->flags |= SRB_ABORT_PENDING; DEBUG11(printk("qla2x00_abort_command(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -848,7 +848,7 @@ qla2x00_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; mcp->mb[0] = MBC_ABORT_TARGET; @@ -872,11 +872,11 @@ qla2x00_abort_target(fc_port_t *fcport) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -912,7 +912,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->out_mb = MBX_0; @@ -933,11 +933,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -968,7 +968,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; @@ -980,7 +980,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { /* Convert returned data and check our values. */ *r_a_tov = mcp->mb[3] / 2; @@ -992,7 +992,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, } DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d " - "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);) + "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov)); } return rval; @@ -1023,7 +1023,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; mcp->mb[2] = MSW(ha->init_cb_dma); @@ -1043,11 +1043,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x " "mb0=%x.\n", - ha->host_no, rval, mcp->mb[0]);) + ha->host_no, rval, mcp->mb[0])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1079,7 +1079,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) struct port_database_24xx *pd24; dma_addr_t pd_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); pd24 = NULL; pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); @@ -1220,7 +1220,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; @@ -1235,11 +1235,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): " - "failed=%x.\n", ha->host_no, rval);) + "failed=%x.\n", ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1272,7 +1272,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_PORT_NAME; mcp->out_mb = MBX_1|MBX_0; @@ -1292,7 +1292,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { if (name != NULL) { /* This function returns name in big endian. */ @@ -1307,7 +1307,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1335,7 +1335,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; @@ -1364,10 +1364,10 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -1400,10 +1400,10 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n", - ha->host_no);) + ha->host_no)); DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total " - "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);) + "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov)); mcp->mb[0] = MBC_SEND_SNS_COMMAND; mcp->mb[1] = cmd_size; @@ -1421,12 +1421,12 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { /*EMPTY*/ - DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);) + DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no)); } return rval; @@ -1442,7 +1442,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, dma_addr_t lg_dma; uint32_t iop[2]; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1458,13 +1458,15 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI); + if (opt & BIT_1) + lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1505,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, break; } } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); iop[0] = le32_to_cpu(lg->io_parameter[0]); @@ -1559,7 +1561,7 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -1604,11 +1606,11 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x " "mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[2]);) + mcp->mb[0], mcp->mb[1], mcp->mb[2])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1643,7 +1645,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, mb_ret, opt); - DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_LOGIN_LOOP_PORT; if (HAS_EXTENDED_IDS(ha)) @@ -1677,13 +1679,13 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); } else { /*EMPTY*/ - DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return (rval); @@ -1697,7 +1699,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, struct logio_entry_24xx *lg; dma_addr_t lg_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1718,7 +1720,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1729,10 +1731,10 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, "-- completion status (%x) ioparam=%x/%x.\n", __func__, ha->host_no, le16_to_cpu(lg->comp_status), le32_to_cpu(lg->io_parameter[0]), - le32_to_cpu(lg->io_parameter[1]));) + le32_to_cpu(lg->io_parameter[1]))); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1765,7 +1767,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; mcp->out_mb = MBX_1|MBX_0; @@ -1785,11 +1787,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x " - "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);) + "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1818,7 +1820,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LIP_FULL_LOGIN; mcp->mb[1] = 0; @@ -1833,11 +1835,11 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1864,7 +1866,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n", - ha->host_no);) + ha->host_no)); if (id_list == NULL) return QLA_FUNCTION_FAILED; @@ -1893,11 +1895,11 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { *entries = mcp->mb[1]; DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1936,7 +1938,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__, - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x " "mb7=%x mb10=%x.\n", __func__, ha->host_no, @@ -2045,7 +2047,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, link_stat_t *stat_buf; dma_addr_t stat_buf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma); if (stat_buf == NULL) { @@ -2083,7 +2085,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, if (rval == QLA_SUCCESS) { if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n", - __func__, ha->host_no, mcp->mb[0]);) + __func__, ha->host_no, mcp->mb[0])); status[0] = mcp->mb[0]; rval = BIT_1; } else { @@ -2108,12 +2110,12 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt, stat_buf->prim_seq_err_cnt, stat_buf->inval_xmit_word_cnt, - stat_buf->inval_crc_cnt);) + stat_buf->inval_crc_cnt)); } } else { /* Failed. */ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, - ha->host_no, rval);) + ha->host_no, rval)); rval = BIT_1; } @@ -2132,7 +2134,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords, uint32_t *sbuf, *siter; dma_addr_t sbuf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (dwords > (DMA_POOL_SIZE / 4)) { DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs " @@ -2196,7 +2198,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) dma_addr_t abt_dma; uint32_t handle; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); fcport = sp->fcport; @@ -2229,7 +2231,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else if (abt->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -2238,10 +2240,10 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) } else if (abt->nport_handle != __constant_cpu_to_le16(0)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, ha->host_no, - le16_to_cpu(abt->nport_handle));) + le16_to_cpu(abt->nport_handle))); rval = QLA_FUNCTION_FAILED; } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); sp->flags |= SRB_ABORT_PENDING; } @@ -2268,7 +2270,7 @@ qla24xx_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); @@ -2290,7 +2292,7 @@ qla24xx_abort_target(fc_port_t *fcport) rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); goto atarget_done; } else if (tsk->p.sts.entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " @@ -2302,7 +2304,7 @@ qla24xx_abort_target(fc_port_t *fcport) __constant_cpu_to_le16(CS_COMPLETE)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, - ha->host_no, le16_to_cpu(tsk->p.sts.comp_status));) + ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); rval = QLA_FUNCTION_FAILED; goto atarget_done; } @@ -2311,9 +2313,9 @@ qla24xx_abort_target(fc_port_t *fcport) rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } atarget_done: @@ -2460,3 +2462,81 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha) return rval; } + +int +qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, + uint16_t buffers) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = ctrl; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + if (ctrl == TC_ENABLE) { + mcp->mb[2] = LSW(eft_dma); + mcp->mb[3] = MSW(eft_dma); + mcp->mb[4] = LSW(MSD(eft_dma)); + mcp->mb[5] = MSW(MSD(eft_dma)); + mcp->mb[6] = buffers; + mcp->mb[7] = buffers; + mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2; + } + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +int +qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, + uint16_t off, uint16_t count) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_READ_SFP; + mcp->mb[1] = addr; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = count; + mcp->mb[9] = off; + mcp->mb[10] = 0; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + ha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 93062593ebe..ec7ebb6037e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -39,14 +39,14 @@ MODULE_PARM_DESC(ql2xlogintimeout, int qlport_down_retry = 30; module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(qlport_down_retry, - "Maximum number of command retries to a port that returns" + "Maximum number of command retries to a port that returns " "a PORT-DOWN status."); int ql2xplogiabsentdevice; module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xplogiabsentdevice, "Option to enable PLOGI to devices that are not present after " - "a Fabric scan. This is needed for several broken switches." + "a Fabric scan. This is needed for several broken switches. " "Default is 0 - no PLOGI. 1 - perfom PLOGI."); int ql2xloginretrycount = 0; @@ -54,6 +54,19 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); +int ql2xallocfwdump = 1; +module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xallocfwdump, + "Option to enable allocation of memory for a firmware dump " + "during HBA initialization. Memory allocation requirements " + "vary by ISP type. Default is 1 - allocate memory."); + +int extended_error_logging; +module_param(extended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging. 1 - log errors."); + static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); @@ -624,7 +637,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", __func__, ha->host_no, sp, serial)); - DEBUG3(qla2x00_print_scsi_cmd(cmd);) + DEBUG3(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops.abort_command(ha, sp)) { @@ -766,7 +779,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) #endif } else { DEBUG2(printk(KERN_INFO - "%s failed: loop not ready\n",__func__);) + "%s failed: loop not ready\n",__func__)); } if (ret == FAILED) { @@ -1021,12 +1034,12 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) /* Empty */ DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", __func__, - ha->host_no);) + ha->host_no)); } else { /* Empty */ DEBUG3(printk("%s(%ld): exiting normally.\n", __func__, - ha->host_no);) + ha->host_no)); } return(status); @@ -1324,7 +1337,8 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha) /* * PCI driver interface */ -static int qla2x00_probe_one(struct pci_dev *pdev) +static int __devinit +qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; device_reg_t __iomem *reg; @@ -1405,7 +1419,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla2x00_read_nvram_data; ha->isp_ops.write_nvram = qla2x00_write_nvram_data; ha->isp_ops.fw_dump = qla2100_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; ha->isp_ops.read_optrom = qla2x00_read_optrom_data; ha->isp_ops.write_optrom = qla2x00_write_optrom_data; if (IS_QLA2100(ha)) { @@ -1432,7 +1445,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.pci_config = qla2300_pci_config; ha->isp_ops.intr_handler = qla2300_intr_handler; ha->isp_ops.fw_dump = qla2300_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; ha->isp_ops.beacon_on = qla2x00_beacon_on; ha->isp_ops.beacon_off = qla2x00_beacon_off; ha->isp_ops.beacon_blink = qla2x00_beacon_blink; @@ -1469,7 +1481,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla24xx_read_nvram_data; ha->isp_ops.write_nvram = qla24xx_write_nvram_data; ha->isp_ops.fw_dump = qla24xx_fw_dump; - ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; ha->isp_ops.read_optrom = qla24xx_read_optrom_data; ha->isp_ops.write_optrom = qla24xx_write_optrom_data; ha->isp_ops.beacon_on = qla24xx_beacon_on; @@ -1640,7 +1651,8 @@ probe_out: return ret; } -static void qla2x00_remove_one(struct pci_dev *pdev) +static void __devexit +qla2x00_remove_one(struct pci_dev *pdev) { scsi_qla_host_t *ha; @@ -1678,6 +1690,9 @@ qla2x00_free_device(scsi_qla_host_t *ha) kthread_stop(t); } + if (ha->eft) + qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + /* Stop currently executing firmware. */ qla2x00_stop_firmware(ha); @@ -1899,17 +1914,6 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) } memset(ha->init_cb, 0, ha->init_cb_size); - /* Allocate ioctl related memory. */ - if (qla2x00_alloc_ioctl_mem(ha)) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - ioctl_mem\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - if (qla2x00_allocate_sp_pool(ha)) { qla_printk(KERN_WARNING, ha, "Memory Allocation failed - " @@ -1972,6 +1976,26 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) continue; } memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + /* + * Get consistent memory allocated for SFP + * block. + */ + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, + GFP_KERNEL, &ha->sfp_data_dma); + if (ha->sfp_data == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "sfp_data\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); + } } /* Done all allocations without any error. */ @@ -2006,12 +2030,16 @@ qla2x00_mem_free(scsi_qla_host_t *ha) return; } - /* free ioctl memory */ - qla2x00_free_ioctl_mem(ha); - /* free sp pool */ qla2x00_free_sp_pool(ha); + if (ha->fw_dump) { + if (ha->eft) + dma_free_coherent(&ha->pdev->dev, + ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); + vfree(ha->fw_dump); + } + if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); @@ -2020,6 +2048,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); + if (ha->sfp_data) + dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); + if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); @@ -2043,6 +2074,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); + ha->eft = NULL; + ha->eft_dma = 0; ha->sns_cmd = NULL; ha->sns_cmd_dma = 0; ha->ct_sns = NULL; @@ -2071,13 +2104,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } INIT_LIST_HEAD(&ha->fcports); - vfree(ha->fw_dump); - vfree(ha->fw_dump_buffer); - ha->fw_dump = NULL; ha->fw_dumped = 0; ha->fw_dump_reading = 0; - ha->fw_dump_buffer = NULL; vfree(ha->optrom_buffer); } @@ -2617,40 +2646,16 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); -static int __devinit -qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - return qla2x00_probe_one(pdev); -} - -static void __devexit -qla2xxx_remove_one(struct pci_dev *pdev) -{ - qla2x00_remove_one(pdev); -} - static struct pci_driver qla2xxx_pci_driver = { .name = QLA2XXX_DRIVER_NAME, .driver = { .owner = THIS_MODULE, }, .id_table = qla2xxx_pci_tbl, - .probe = qla2xxx_probe_one, - .remove = __devexit_p(qla2xxx_remove_one), + .probe = qla2x00_probe_one, + .remove = __devexit_p(qla2x00_remove_one), }; -static inline int -qla2x00_pci_module_init(void) -{ - return pci_module_init(&qla2xxx_pci_driver); -} - -static inline void -qla2x00_pci_module_exit(void) -{ - pci_unregister_driver(&qla2xxx_pci_driver); -} - /** * qla2x00_module_init - Module initialization. **/ @@ -2670,16 +2675,16 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); -#if DEBUG_QLA2100 - strcat(qla2x00_version_str, "-debug"); -#endif + if (extended_error_logging) + strcat(qla2x00_version_str, "-debug"); + qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) return -ENODEV; printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); - ret = qla2x00_pci_module_init(); + ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); @@ -2693,7 +2698,7 @@ qla2x00_module_init(void) static void __exit qla2x00_module_exit(void) { - qla2x00_pci_module_exit(); + pci_unregister_driver(&qla2xxx_pci_driver); qla2x00_release_firmware(); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 6b315521bd8..d2d68344065 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.05-k2" +#define QLA2XXX_VERSION "8.01.05-k3" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index e1168860045..9c63b00773c 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -50,18 +50,22 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.75" -static const char * scsi_debug_version_date = "20050113"; +#define SCSI_DEBUG_VERSION "1.79" +static const char * scsi_debug_version_date = "20060604"; /* Additional Sense Code (ASC) used */ -#define NO_ADDED_SENSE 0x0 +#define NO_ADDITIONAL_SENSE 0x0 +#define LOGICAL_UNIT_NOT_READY 0x4 #define UNRECOVERED_READ_ERR 0x11 +#define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define ADDR_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 +#define INVALID_FIELD_IN_PARAM_LIST 0x26 #define POWERON_RESET 0x29 #define SAVING_PARAMS_UNSUP 0x39 -#define THRESHHOLD_EXCEEDED 0x5d +#define THRESHOLD_EXCEEDED 0x5d +#define LOW_POWER_COND_ON 0x5e #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ @@ -80,6 +84,8 @@ static const char * scsi_debug_version_date = "20050113"; #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ #define DEF_PTYPE 0 #define DEF_D_SENSE 0 +#define DEF_NO_LUN_0 0 +#define DEF_VIRTUAL_GB 0 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -106,6 +112,7 @@ static const char * scsi_debug_version_date = "20050113"; /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) * or "peripheral device" addressing (value 0) */ #define SAM2_LUN_ADDRESS_METHOD 0 +#define SAM2_WLUN_REPORT_LUNS 0xc101 static int scsi_debug_add_host = DEF_NUM_HOST; static int scsi_debug_delay = DEF_DELAY; @@ -118,13 +125,16 @@ static int scsi_debug_opts = DEF_OPTS; static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ static int scsi_debug_dsense = DEF_D_SENSE; +static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; +static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; static int scsi_debug_cmnd_count = 0; #define DEV_READONLY(TGT) (0) #define DEV_REMOVEABLE(TGT) (0) -static unsigned long sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ /* old BIOS stuff, kernel may get rid of them but some mode sense pages @@ -149,7 +159,9 @@ struct sdebug_dev_info { unsigned int target; unsigned int lun; struct sdebug_host_info *sdbg_host; + unsigned int wlun; char reset; + char stopped; char used; }; @@ -193,11 +205,11 @@ static struct scsi_host_template sdebug_driver_template = { .bios_param = scsi_debug_biosparam, .can_queue = SCSI_DEBUG_CANQUEUE, .this_id = 7, - .sg_tablesize = 64, - .cmd_per_lun = 3, - .max_sectors = 4096, + .sg_tablesize = 256, + .cmd_per_lun = 16, + .max_sectors = 0xffff, .unchecked_isa_dma = 0, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, .module = THIS_MODULE, }; @@ -225,19 +237,32 @@ static struct device_driver sdebug_driverfs_driver = { static const int check_condition_result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; +static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b}; +static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + /* function declarations */ static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, struct sdebug_dev_info * devip); static int resp_requests(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); +static int resp_start_stop(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); static int resp_readcap(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); -static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, +static int resp_readcap16(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_mode_sense(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip); -static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip); -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip); +static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, + struct sdebug_dev_info * devip); +static int resp_log_sense(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); +static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip); +static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip); static int resp_report_luns(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, @@ -248,8 +273,8 @@ static void timer_intr_handler(unsigned long); static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, int asc, int asq); -static int check_reset(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); +static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, + struct sdebug_dev_info * devip); static int schedule_resp(struct scsi_cmnd * cmnd, struct sdebug_dev_info * devip, done_funct_t done, int scsi_result, int delta_jiff); @@ -257,8 +282,10 @@ static void __init sdebug_build_parts(unsigned char * ramp); static void __init init_all_queued(void); static void stop_all_queued(void); static int stop_queued_cmnd(struct scsi_cmnd * cmnd); -static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, - const char * dev_id_str, int dev_id_str_len); +static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, + int dev_id_num, const char * dev_id_str, + int dev_id_str_len); +static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); static void do_create_driverfs_files(void); static void do_remove_driverfs_files(void); @@ -274,18 +301,22 @@ static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int block, upper_blk, num, k; + int len, k, j; + unsigned int num; + unsigned long long lba; int errsts = 0; - int target = scmd_id(SCpnt); + int target = SCpnt->device->id; struct sdebug_dev_info * devip = NULL; int inj_recovered = 0; + int delay_override = 0; if (done == NULL) return 0; /* assume mid level reprocessing command */ + SCpnt->resid = 0; if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); - for (k = 0, num = SCpnt->cmd_len; k < num; ++k) + for (k = 0, len = SCpnt->cmd_len; k < len; ++k) printk("%02x ", (int)cmd[k]); printk("\n"); } @@ -296,7 +327,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) DID_NO_CONNECT << 16, 0); } - if (SCpnt->device->lun >= scsi_debug_max_luns) + if ((SCpnt->device->lun >= scsi_debug_max_luns) && + (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) return schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16, 0); devip = devInfoReg(SCpnt->device); @@ -315,118 +347,150 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) inj_recovered = 1; /* to reads and writes below */ } + if (devip->wlun) { + switch (*cmd) { + case INQUIRY: + case REQUEST_SENSE: + case TEST_UNIT_READY: + case REPORT_LUNS: + break; /* only allowable wlun commands */ + default: + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Opcode: 0x%x " + "not supported for wlun\n", *cmd); + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + return schedule_resp(SCpnt, devip, done, errsts, + 0); + } + } + switch (*cmd) { case INQUIRY: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_inquiry(SCpnt, target, devip); break; case REQUEST_SENSE: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_requests(SCpnt, devip); break; case REZERO_UNIT: /* actually this is REWIND for SSC */ case START_STOP: - errsts = check_reset(SCpnt, devip); + errsts = resp_start_stop(SCpnt, devip); break; case ALLOW_MEDIUM_REMOVAL: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 1, devip))) break; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Medium removal %s\n", cmd[4] ? "inhibited" : "enabled"); break; case SEND_DIAGNOSTIC: /* mandatory */ - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case TEST_UNIT_READY: /* mandatory */ - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); break; case RESERVE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RESERVE_10: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE_10: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case READ_CAPACITY: errsts = resp_readcap(SCpnt, devip); break; + case SERVICE_ACTION_IN: + if (SAI_READ_CAPACITY_16 != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_readcap16(SCpnt, devip); + break; case READ_16: case READ_12: case READ_10: case READ_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == READ_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == READ_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == READ_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* READ (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_read(SCpnt, upper_blk, block, num, devip); + errsts = resp_read(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_report_luns(SCpnt, devip); break; case VERIFY: /* 10 byte SBC-2 command */ - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 0, devip); break; case WRITE_16: case WRITE_12: case WRITE_10: case WRITE_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == WRITE_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == WRITE_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == WRITE_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* WRITE (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_write(SCpnt, upper_blk, block, num, devip); + errsts = resp_write(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; @@ -434,20 +498,31 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) case MODE_SENSE_10: errsts = resp_mode_sense(SCpnt, target, devip); break; + case MODE_SELECT: + errsts = resp_mode_select(SCpnt, 1, devip); + break; + case MODE_SELECT_10: + errsts = resp_mode_select(SCpnt, 0, devip); + break; + case LOG_SENSE: + errsts = resp_log_sense(SCpnt, devip); + break; case SYNCHRONIZE_CACHE: - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " "supported\n", *cmd); - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 1, devip))) break; /* Unit attention takes precedence */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); errsts = check_condition_result; break; } - return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay); + return schedule_resp(SCpnt, devip, done, errsts, + (delay_override ? 0 : scsi_debug_delay)); } static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) @@ -459,7 +534,8 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) /* return -ENOTTY; // correct return but upsets fdisk */ } -static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) +static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, + struct sdebug_dev_info * devip) { if (devip->reset) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) @@ -469,6 +545,14 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); return check_condition_result; } + if ((0 == reset_only) && devip->stopped) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Reporting Not " + "ready: initializing command required\n"); + mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, + 0x2); + return check_condition_result; + } return 0; } @@ -492,7 +576,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, req_len = scp->request_bufflen; act_len = (req_len < arr_len) ? req_len : arr_len; memcpy(scp->request_buffer, arr, act_len); - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } sgpnt = (struct scatterlist *)scp->request_buffer; @@ -515,7 +602,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, } req_len += sgpnt->length; } - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } @@ -566,12 +656,14 @@ static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char * inq_product_rev = "0004"; -static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, - const char * dev_id_str, int dev_id_str_len) +static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, + int dev_id_num, const char * dev_id_str, + int dev_id_str_len) { - int num; + int num, port_a; + char b[32]; - /* Two identification descriptors: */ + port_a = target_dev_id + 1; /* T10 vendor identifier field format (faked) */ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; @@ -582,25 +674,246 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, num = 8 + 16 + dev_id_str_len; arr[3] = num; num += 4; - /* NAA IEEE registered identifier (faked) */ - arr[num] = 0x1; /* binary */ - arr[num + 1] = 0x3; - arr[num + 2] = 0x0; - arr[num + 3] = 0x8; - arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ - arr[num + 5] = 0x23; - arr[num + 6] = 0x45; - arr[num + 7] = 0x60; - arr[num + 8] = (dev_id_num >> 24); - arr[num + 9] = (dev_id_num >> 16) & 0xff; - arr[num + 10] = (dev_id_num >> 8) & 0xff; - arr[num + 11] = dev_id_num & 0xff; - return num + 12; + if (dev_id_num >= 0) { + /* NAA-5, Logical unit identifier (binary) */ + arr[num++] = 0x1; /* binary (not necessarily sas) */ + arr[num++] = 0x3; /* PIV=0, lu, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ + arr[num++] = 0x33; + arr[num++] = 0x33; + arr[num++] = 0x30; + arr[num++] = (dev_id_num >> 24); + arr[num++] = (dev_id_num >> 16) & 0xff; + arr[num++] = (dev_id_num >> 8) & 0xff; + arr[num++] = dev_id_num & 0xff; + /* Target relative port number */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x94; /* PIV=1, target port, rel port */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x4; /* length */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port A */ + } + /* NAA-5, Target port identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* piv=1, target port, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + /* NAA-5, Target device identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0xa3; /* piv=1, target device, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (target_dev_id >> 24); + arr[num++] = (target_dev_id >> 16) & 0xff; + arr[num++] = (target_dev_id >> 8) & 0xff; + arr[num++] = target_dev_id & 0xff; + /* SCSI name string: Target device identifier */ + arr[num++] = 0x63; /* proto=sas, UTF-8 */ + arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ + arr[num++] = 0x0; + arr[num++] = 24; + memcpy(arr + num, "naa.52222220", 12); + num += 12; + snprintf(b, sizeof(b), "%08X", target_dev_id); + memcpy(arr + num, b, 8); + num += 8; + memset(arr + num, 0, 4); + num += 4; + return num; +} + + +static unsigned char vpd84_data[] = { +/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, + 0x22,0x22,0x22,0x0,0xbb,0x1, + 0x22,0x22,0x22,0x0,0xbb,0x2, +}; + +static int inquiry_evpd_84(unsigned char * arr) +{ + memcpy(arr, vpd84_data, sizeof(vpd84_data)); + return sizeof(vpd84_data); +} + +static int inquiry_evpd_85(unsigned char * arr) +{ + int num = 0; + const char * na1 = "https://www.kernel.org/config"; + const char * na2 = "http://www.kernel.org/log"; + int plen, olen; + + arr[num++] = 0x1; /* lu, storage config */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na1); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null termianted, padded */ + memcpy(arr + num, na1, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + arr[num++] = 0x4; /* lu, logging */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na2); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null terminated, padded */ + memcpy(arr + num, na2, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + return num; +} + +/* SCSI ports VPD page */ +static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) +{ + int num = 0; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port 1 (primary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (A) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x2; /* relative port 2 (secondary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (B) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_b >> 24); + arr[num++] = (port_b >> 16) & 0xff; + arr[num++] = (port_b >> 8) & 0xff; + arr[num++] = port_b & 0xff; + + return num; +} + + +static unsigned char vpd89_data[] = { +/* from 4th byte */ 0,0,0,0, +'l','i','n','u','x',' ',' ',' ', +'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', +'1','2','3','4', +0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +0xec,0,0,0, +0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, +0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, +0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, +0x53,0x41, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x10,0x80, +0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, +0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, +0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, +0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, +0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, +0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, +0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, +0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, +0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, +}; + +static int inquiry_evpd_89(unsigned char * arr) +{ + memcpy(arr, vpd89_data, sizeof(vpd89_data)); + return sizeof(vpd89_data); +} + + +static unsigned char vpdb0_data[] = { + /* from 4th byte */ 0,0,0,4, + 0,0,0x4,0, + 0,0,0,64, +}; + +static int inquiry_evpd_b0(unsigned char * arr) +{ + memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); + if (sdebug_store_sectors > 0x400) { + arr[4] = (sdebug_store_sectors >> 24) & 0xff; + arr[5] = (sdebug_store_sectors >> 16) & 0xff; + arr[6] = (sdebug_store_sectors >> 8) & 0xff; + arr[7] = sdebug_store_sectors & 0xff; + } + return sizeof(vpdb0_data); } #define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 128 +#define SDEBUG_MAX_INQ_ARR_SZ 584 static int resp_inquiry(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) @@ -608,64 +921,113 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, unsigned char pq_pdt; unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len; + int alloc_len, n; alloc_len = (cmd[3] << 8) + cmd[4]; memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); - pq_pdt = (scsi_debug_ptype & 0x1f); + if (devip->wlun) + pq_pdt = 0x1e; /* present, wlun */ + else if (scsi_debug_no_lun_0 && (0 == devip->lun)) + pq_pdt = 0x7f; /* not present, no device type */ + else + pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int dev_id_num, len; - char dev_id_str[6]; + int lu_id_num, target_dev_id, len; + char lu_id_str[6]; + int host_no = devip->sdbg_host->shost->host_no; - dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) + - (devip->target * 1000) + devip->lun; - len = scnprintf(dev_id_str, 6, "%d", dev_id_num); + lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + + (devip->target * 1000) + devip->lun); + target_dev_id = ((host_no + 1) * 2000) + + (devip->target * 1000) - 3; + len = scnprintf(lu_id_str, 6, "%d", lu_id_num); if (0 == cmd[2]) { /* supported vital product data pages */ - arr[3] = 3; - arr[4] = 0x0; /* this page */ - arr[5] = 0x80; /* unit serial number */ - arr[6] = 0x83; /* device identification */ + arr[1] = cmd[2]; /*sanity */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0x80; /* unit serial number */ + arr[n++] = 0x83; /* device identification */ + arr[n++] = 0x84; /* software interface ident. */ + arr[n++] = 0x85; /* management network addresses */ + arr[n++] = 0x86; /* extended inquiry */ + arr[n++] = 0x87; /* mode page policy */ + arr[n++] = 0x88; /* SCSI ports */ + arr[n++] = 0x89; /* ATA information */ + arr[n++] = 0xb0; /* Block limits (SBC) */ + arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ - arr[1] = 0x80; + arr[1] = cmd[2]; /*sanity */ arr[3] = len; - memcpy(&arr[4], dev_id_str, len); + memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ - arr[1] = 0x83; - arr[3] = inquiry_evpd_83(&arr[4], dev_id_num, - dev_id_str, len); + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, + lu_id_num, lu_id_str, len); + } else if (0x84 == cmd[2]) { /* Software interface ident. */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_84(&arr[4]); + } else if (0x85 == cmd[2]) { /* Management network addresses */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_85(&arr[4]); + } else if (0x86 == cmd[2]) { /* extended inquiry */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x3c; /* number of following entries */ + arr[4] = 0x0; /* no protection stuff */ + arr[5] = 0x7; /* head of q, ordered + simple q's */ + } else if (0x87 == cmd[2]) { /* mode page policy */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x8; /* number of following entries */ + arr[4] = 0x2; /* disconnect-reconnect mp */ + arr[6] = 0x80; /* mlus, shared */ + arr[8] = 0x18; /* protocol specific lu */ + arr[10] = 0x82; /* mlus, per initiator port */ + } else if (0x88 == cmd[2]) { /* SCSI Ports */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); + } else if (0x89 == cmd[2]) { /* ATA information */ + arr[1] = cmd[2]; /*sanity */ + n = inquiry_evpd_89(&arr[4]); + arr[2] = (n >> 8); + arr[3] = (n & 0xff); + } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_b0(&arr[4]); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); return fill_from_dev_buffer(scp, arr, - min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); + min(len, SDEBUG_MAX_INQ_ARR_SZ)); } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; - arr[6] = 0x1; /* claim: ADDR16 */ + arr[6] = 0x10; /* claim: MultiP */ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ - arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ + arr[7] = 0xa; /* claim: LINKED + CMDQUE */ memcpy(&arr[8], inq_vendor_id, 8); memcpy(&arr[16], inq_product_id, 16); memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ - arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ - arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ + arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ + arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ + n = 62; if (scsi_debug_ptype == 0) { - arr[62] = 0x1; arr[63] = 0x80; /* SBC */ + arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ } else if (scsi_debug_ptype == 1) { - arr[62] = 0x2; arr[63] = 0x00; /* SSC */ + arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ } + arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ return fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); } @@ -676,46 +1038,141 @@ static int resp_requests(struct scsi_cmnd * scp, unsigned char * sbuff; unsigned char *cmd = (unsigned char *)scp->cmnd; unsigned char arr[SDEBUG_SENSE_LEN]; + int want_dsense; int len = 18; - memset(arr, 0, SDEBUG_SENSE_LEN); + memset(arr, 0, sizeof(arr)); if (devip->reset == 1) - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); + want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; sbuff = devip->sense_buff; - if ((cmd[1] & 1) && (! scsi_debug_dsense)) { - /* DESC bit set and sense_buff in fixed format */ - arr[0] = 0x72; - arr[1] = sbuff[2]; /* sense key */ - arr[2] = sbuff[12]; /* asc */ - arr[3] = sbuff[13]; /* ascq */ - len = 8; - } else + if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = THRESHOLD_EXCEEDED; + arr[3] = 0xff; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = THRESHOLD_EXCEEDED; + arr[13] = 0xff; /* TEST set and MRIE==6 */ + } + } else if (devip->stopped) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = LOW_POWER_COND_ON; + arr[3] = 0x0; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = LOW_POWER_COND_ON; + arr[13] = 0x0; /* TEST set and MRIE==6 */ + } + } else { memcpy(arr, sbuff, SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + if ((cmd[1] & 1) && (! scsi_debug_dsense)) { + /* DESC bit set and sense_buff in fixed format */ + memset(arr, 0, sizeof(arr)); + arr[0] = 0x72; + arr[1] = sbuff[2]; /* sense key */ + arr[2] = sbuff[12]; /* asc */ + arr[3] = sbuff[13]; /* ascq */ + len = 8; + } + } + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); return fill_from_dev_buffer(scp, arr, len); } +static int resp_start_stop(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + int power_cond, errsts, start; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + power_cond = (cmd[4] & 0xf0) >> 4; + if (power_cond) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } + start = cmd[4] & 1; + if (start == devip->stopped) + devip->stopped = !start; + return 0; +} + #define SDEBUG_READCAP_ARR_SZ 8 static int resp_readcap(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned char arr[SDEBUG_READCAP_ARR_SZ]; - unsigned long capac; + unsigned int capac; int errsts; - if ((errsts = check_reset(scp, devip))) + if ((errsts = check_readiness(scp, 1, devip))) return errsts; + /* following just in case virtual_gb changed */ + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; memset(arr, 0, SDEBUG_READCAP_ARR_SZ); - capac = (unsigned long)sdebug_capacity - 1; - arr[0] = (capac >> 24); - arr[1] = (capac >> 16) & 0xff; - arr[2] = (capac >> 8) & 0xff; - arr[3] = capac & 0xff; + if (sdebug_capacity < 0xffffffff) { + capac = (unsigned int)sdebug_capacity - 1; + arr[0] = (capac >> 24); + arr[1] = (capac >> 16) & 0xff; + arr[2] = (capac >> 8) & 0xff; + arr[3] = capac & 0xff; + } else { + arr[0] = 0xff; + arr[1] = 0xff; + arr[2] = 0xff; + arr[3] = 0xff; + } arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; arr[7] = SECT_SIZE_PER(target) & 0xff; return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } +#define SDEBUG_READCAP16_ARR_SZ 32 +static int resp_readcap16(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; + unsigned long long capac; + int errsts, k, alloc_len; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) + + cmd[13]); + /* following just in case virtual_gb changed */ + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; + memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); + capac = sdebug_capacity - 1; + for (k = 0; k < 8; ++k, capac >>= 8) + arr[7 - k] = capac & 0xff; + arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; + arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; + arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; + arr[11] = SECT_SIZE_PER(target) & 0xff; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); +} + /* <<Following mode page info copied from ST318451LW>> */ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) @@ -771,27 +1228,98 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target) static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) { /* Control mode page for mode_sense */ - unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; + unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; if (scsi_debug_dsense) ctrl_m_pg[2] |= 0x4; + else + ctrl_m_pg[2] &= ~0x4; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); + memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); return sizeof(ctrl_m_pg); } + static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ - unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; + unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(iec_m_pg) - 2); + memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); return sizeof(iec_m_pg); } +static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) +{ /* SAS SSP mode page - short format for mode_sense */ + unsigned char sas_sf_m_pg[] = {0x19, 0x6, + 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; + + memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); + return sizeof(sas_sf_m_pg); +} + + +static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, + int target_dev_id) +{ /* SAS phy control and discover mode page for mode_sense */ + unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, + 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x2, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x3, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); + p[20] = (port_a >> 24); + p[21] = (port_a >> 16) & 0xff; + p[22] = (port_a >> 8) & 0xff; + p[23] = port_a & 0xff; + p[48 + 20] = (port_b >> 24); + p[48 + 21] = (port_b >> 16) & 0xff; + p[48 + 22] = (port_b >> 8) & 0xff; + p[48 + 23] = port_b & 0xff; + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); + return sizeof(sas_pcd_m_pg); +} + +static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) +{ /* SAS SSP shared protocol specific port mode subpage */ + unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); + return sizeof(sas_sha_m_pg); +} + #define SDEBUG_MAX_MSENSE_SZ 256 static int resp_mode_sense(struct scsi_cmnd * scp, int target, @@ -800,12 +1328,12 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, unsigned char dbd; int pcontrol, pcode, subpcode; unsigned char dev_spec; - int alloc_len, msense_6, offset, len, errsts; + int alloc_len, msense_6, offset, len, errsts, target_dev_id; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - if ((errsts = check_reset(scp, devip))) + if ((errsts = check_readiness(scp, 1, devip))) return errsts; dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; @@ -819,6 +1347,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, 0); return check_condition_result; } + target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + + (devip->target * 1000) - 3; dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; if (msense_6) { arr[2] = dev_spec; @@ -829,7 +1359,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, } ap = arr + offset; - if (0 != subpcode) { /* TODO: Control Extension page */ + if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { + /* TODO: Control Extension page */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -855,17 +1386,45 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, len = resp_ctrl_m_pg(ap, pcontrol, target); offset += len; break; + case 0x19: /* if spc==1 then sas phy, control+discover */ + if ((subpcode > 0x2) && (subpcode < 0xff)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = 0; + if ((0x0 == subpcode) || (0xff == subpcode)) + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if ((0x1 == subpcode) || (0xff == subpcode)) + len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, + target_dev_id); + if ((0x2 == subpcode) || (0xff == subpcode)) + len += resp_sas_sha_m_spg(ap + len, pcontrol); + offset += len; + break; case 0x1c: /* Informational Exceptions Mode page, all devices */ len = resp_iec_m_pg(ap, pcontrol, target); offset += len; break; case 0x3f: /* Read all Mode pages */ - len = resp_err_recov_pg(ap, pcontrol, target); - len += resp_disconnect_pg(ap + len, pcontrol, target); - len += resp_format_pg(ap + len, pcontrol, target); - len += resp_caching_pg(ap + len, pcontrol, target); - len += resp_ctrl_m_pg(ap + len, pcontrol, target); - len += resp_iec_m_pg(ap + len, pcontrol, target); + if ((0 == subpcode) || (0xff == subpcode)) { + len = resp_err_recov_pg(ap, pcontrol, target); + len += resp_disconnect_pg(ap + len, pcontrol, target); + len += resp_format_pg(ap + len, pcontrol, target); + len += resp_caching_pg(ap + len, pcontrol, target); + len += resp_ctrl_m_pg(ap + len, pcontrol, target); + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if (0xff == subpcode) { + len += resp_sas_pcd_m_spg(ap + len, pcontrol, + target, target_dev_id); + len += resp_sas_sha_m_spg(ap + len, pcontrol); + } + len += resp_iec_m_pg(ap + len, pcontrol, target); + } else { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } offset += len; break; default: @@ -882,71 +1441,274 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); } -static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip) +#define SDEBUG_MAX_MSELECT_SZ 512 + +static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, + struct sdebug_dev_info * devip) +{ + int pf, sp, ps, md_len, bd_len, off, spf, pg_len; + int param_len, res, errsts, mpage; + unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + pf = cmd[1] & 0x10; + sp = cmd[1] & 0x1; + param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); + if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + res = fetch_to_dev_buffer(scp, arr, param_len); + if (-1 == res) + return (DID_ERROR << 16); + else if ((res < param_len) && + (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) + printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " + " IO sent=%d bytes\n", param_len, res); + md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); + bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); + if ((md_len > 2) || (0 != bd_len)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + off = bd_len + (mselect6 ? 4 : 8); + mpage = arr[off] & 0x3f; + ps = !!(arr[off] & 0x80); + if (ps) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + spf = !!(arr[off] & 0x40); + pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : + (arr[off + 1] + 2); + if ((pg_len + off) > param_len) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + PARAMETER_LIST_LENGTH_ERR, 0); + return check_condition_result; + } + switch (mpage) { + case 0xa: /* Control Mode page */ + if (ctrl_m_pg[1] == arr[off + 1]) { + memcpy(ctrl_m_pg + 2, arr + off + 2, + sizeof(ctrl_m_pg) - 2); + scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); + return 0; + } + break; + case 0x1c: /* Informational Exceptions Mode page */ + if (iec_m_pg[1] == arr[off + 1]) { + memcpy(iec_m_pg + 2, arr + off + 2, + sizeof(iec_m_pg) - 2); + return 0; + } + break; + default: + break; + } + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; +} + +static int resp_temp_l_pg(unsigned char * arr) +{ + unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, + 0x0, 0x1, 0x3, 0x2, 0x0, 65, + }; + + memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); + return sizeof(temp_l_pg); +} + +static int resp_ie_l_pg(unsigned char * arr) +{ + unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, + }; + + memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); + if (iec_m_pg[2] & 0x4) { /* TEST bit set */ + arr[4] = THRESHOLD_EXCEEDED; + arr[5] = 0xff; + } + return sizeof(ie_l_pg); +} + +#define SDEBUG_MAX_LSENSE_SZ 512 + +static int resp_log_sense(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n; + unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + ppc = cmd[1] & 0x2; + sp = cmd[1] & 0x1; + if (ppc || sp) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + pcontrol = (cmd[2] & 0xc0) >> 6; + pcode = cmd[2] & 0x3f; + alloc_len = (cmd[7] << 8) + cmd[8]; + arr[0] = pcode; + switch (pcode) { + case 0x0: /* Supported log pages log page */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0xd; /* Temperature */ + arr[n++] = 0x2f; /* Informational exceptions */ + arr[3] = n - 4; + break; + case 0xd: /* Temperature log page */ + arr[3] = resp_temp_l_pg(arr + 4); + break; + case 0x2f: /* Informational exceptions log page */ + arr[3] = resp_ie_l_pg(arr + 4); + break; + default: + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); + return fill_from_dev_buffer(scp, arr, + min(len, SDEBUG_MAX_INQ_ARR_SZ)); +} + +static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip) { unsigned long iflags; + unsigned int block, from_bottom; + unsigned long long u; int ret; - if (upper_blk || (block + num > sdebug_capacity)) { + if (lba + num > sdebug_capacity) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } + /* transfer length excessive (tie in to block limits VPD page) */ + if (num > sdebug_store_sectors) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && - (block <= OPT_MEDIUM_ERR_ADDR) && - ((block + num) > OPT_MEDIUM_ERR_ADDR)) { + (lba <= OPT_MEDIUM_ERR_ADDR) && + ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { + /* claim unrecoverable read error */ mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); - /* claim unrecoverable read error */ + /* set info field and valid bit for fixed descriptor */ + if (0x70 == (devip->sense_buff[0] & 0x7f)) { + devip->sense_buff[0] |= 0x80; /* Valid bit */ + ret = OPT_MEDIUM_ERR_ADDR; + devip->sense_buff[3] = (ret >> 24) & 0xff; + devip->sense_buff[4] = (ret >> 16) & 0xff; + devip->sense_buff[5] = (ret >> 8) & 0xff; + devip->sense_buff[6] = ret & 0xff; + } return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + if ((lba + num) <= sdebug_store_sectors) + ret = fill_from_dev_buffer(SCpnt, + fake_storep + (lba * SECT_SIZE), + num * SECT_SIZE); + else { + /* modulo when one arg is 64 bits needs do_div() */ + u = lba; + block = do_div(u, sdebug_store_sectors); + from_bottom = 0; + if ((block + num) > sdebug_store_sectors) + from_bottom = (block + num) - sdebug_store_sectors; + ret = fill_from_dev_buffer(SCpnt, + fake_storep + (block * SECT_SIZE), + (num - from_bottom) * SECT_SIZE); + if ((0 == ret) && (from_bottom > 0)) + ret = fill_from_dev_buffer(SCpnt, fake_storep, + from_bottom * SECT_SIZE); + } read_unlock_irqrestore(&atomic_rw, iflags); return ret; } -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip) +static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip) { unsigned long iflags; + unsigned int block, to_bottom; + unsigned long long u; int res; - if (upper_blk || (block + num > sdebug_capacity)) { + if (lba + num > sdebug_capacity) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } + /* transfer length excessive (tie in to block limits VPD page) */ + if (num > sdebug_store_sectors) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } write_lock_irqsave(&atomic_rw, iflags); - res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + if ((lba + num) <= sdebug_store_sectors) + res = fetch_to_dev_buffer(SCpnt, + fake_storep + (lba * SECT_SIZE), + num * SECT_SIZE); + else { + /* modulo when one arg is 64 bits needs do_div() */ + u = lba; + block = do_div(u, sdebug_store_sectors); + to_bottom = 0; + if ((block + num) > sdebug_store_sectors) + to_bottom = (block + num) - sdebug_store_sectors; + res = fetch_to_dev_buffer(SCpnt, + fake_storep + (block * SECT_SIZE), + (num - to_bottom) * SECT_SIZE); + if ((0 == res) && (to_bottom > 0)) + res = fetch_to_dev_buffer(SCpnt, fake_storep, + to_bottom * SECT_SIZE); + } write_unlock_irqrestore(&atomic_rw, iflags); if (-1 == res) return (DID_ERROR << 16); else if ((res < (num * SECT_SIZE)) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " + printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " " IO sent=%d bytes\n", num * SECT_SIZE, res); return 0; } -#define SDEBUG_RLUN_ARR_SZ 128 +#define SDEBUG_RLUN_ARR_SZ 256 static int resp_report_luns(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned int alloc_len; - int lun_cnt, i, upper; + int lun_cnt, i, upper, num, n, wlun, lun; unsigned char *cmd = (unsigned char *)scp->cmnd; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; unsigned char arr[SDEBUG_RLUN_ARR_SZ]; + unsigned char * max_addr; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); - if ((alloc_len < 16) || (select_report > 2)) { + if ((alloc_len < 4) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -954,18 +1716,37 @@ static int resp_report_luns(struct scsi_cmnd * scp, /* can produce response with up to 16k luns (lun 0 to lun 16383) */ memset(arr, 0, SDEBUG_RLUN_ARR_SZ); lun_cnt = scsi_debug_max_luns; - arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; - arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; - lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / - sizeof(struct scsi_lun)), lun_cnt); + if (1 == select_report) + lun_cnt = 0; + else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) + --lun_cnt; + wlun = (select_report > 0) ? 1 : 0; + num = lun_cnt + wlun; + arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; + arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; + n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / + sizeof(struct scsi_lun)), num); + if (n < num) { + wlun = 0; + lun_cnt = n; + } one_lun = (struct scsi_lun *) &arr[8]; - for (i = 0; i < lun_cnt; i++) { - upper = (i >> 8) & 0x3f; + max_addr = arr + SDEBUG_RLUN_ARR_SZ; + for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); + ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); + i++, lun++) { + upper = (lun >> 8) & 0x3f; if (upper) one_lun[i].scsi_lun[0] = (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); - one_lun[i].scsi_lun[1] = i & 0xff; + one_lun[i].scsi_lun[1] = lun & 0xff; + } + if (wlun) { + one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; + one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; + i++; } + alloc_len = (unsigned char *)(one_lun + i) - arr; return fill_from_dev_buffer(scp, arr, min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } @@ -1001,7 +1782,8 @@ static void timer_intr_handler(unsigned long indx) static int scsi_debug_slave_alloc(struct scsi_device * sdp) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_alloc\n"); + printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); return 0; } @@ -1010,7 +1792,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) struct sdebug_dev_info * devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_configure\n"); + printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; devip = devInfoReg(sdp); @@ -1018,6 +1801,7 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) if (sdp->host->cmd_per_lun) scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, sdp->host->cmd_per_lun); + blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); return 0; } @@ -1027,7 +1811,8 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp) (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_destroy\n"); + printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (devip) { /* make this slot avaliable for re-use */ devip->used = 0; @@ -1084,6 +1869,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) open_devip->sense_buff[0] = 0x70; open_devip->sense_buff[7] = 0xa; } + if (sdev->lun == SAM2_WLUN_REPORT_LUNS) + open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; return open_devip; } return NULL; @@ -1272,7 +2059,7 @@ static void __init sdebug_build_parts(unsigned char * ramp) printk(KERN_WARNING "scsi_debug:build_parts: reducing " "partitions to %d\n", SDEBUG_MAX_PARTS); } - num_sectors = (int)(sdebug_store_size / SECT_SIZE); + num_sectors = (int)sdebug_store_sectors; sectors_per_part = (num_sectors - sdebug_sectors_per) / scsi_debug_num_parts; heads_by_sects = sdebug_heads * sdebug_sectors_per; @@ -1315,9 +2102,9 @@ static int schedule_resp(struct scsi_cmnd * cmnd, if (scsi_result) { struct scsi_device * sdp = cmnd->device; - sdev_printk(KERN_INFO, sdp, - "non-zero result=0x%x\n", - scsi_result); + printk(KERN_INFO "scsi_debug: <%u %u %u %u> " + "non-zero result=0x%x\n", sdp->host->host_no, + sdp->channel, sdp->id, sdp->lun, scsi_result); } } if (cmnd && devip) { @@ -1364,21 +2151,19 @@ static int schedule_resp(struct scsi_cmnd * cmnd, } } -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly below. - */ -module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */ -module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */ -module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0); -module_param_named(dsense, scsi_debug_dsense, int, 0); -module_param_named(every_nth, scsi_debug_every_nth, int, 0); -module_param_named(max_luns, scsi_debug_max_luns, int, 0); -module_param_named(num_parts, scsi_debug_num_parts, int, 0); -module_param_named(num_tgts, scsi_debug_num_tgts, int, 0); -module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */ -module_param_named(ptype, scsi_debug_ptype, int, 0); -module_param_named(scsi_level, scsi_debug_scsi_level, int, 0); +module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); +module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); +module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); +module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); +module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); +module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); +module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); +module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); +module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); +module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); +module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); +module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); +module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -1387,15 +2172,17 @@ MODULE_VERSION(SCSI_DEBUG_VERSION); MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); -MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs"); -MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)"); +MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); +MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); -MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate"); +MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); +MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); -MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); -MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); +MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); +MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); +MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); static char sdebug_info[256]; @@ -1547,6 +2334,24 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp, DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, sdebug_dsense_store); +static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); +} +static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_no_lun_0 = n; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, + sdebug_no_lun_0_store); + static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); @@ -1622,6 +2427,29 @@ static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) } DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); +static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); +} +static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_virtual_gb = n; + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, + sdebug_virtual_gb_store); + static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); @@ -1691,14 +2519,19 @@ static void do_remove_driverfs_files(void) static int __init scsi_debug_init(void) { - unsigned long sz; + unsigned int sz; int host_to_add; int k; if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ - sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576; - sdebug_capacity = sdebug_store_size / SECT_SIZE; + sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; + sdebug_store_sectors = sdebug_store_size / SECT_SIZE; + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -1812,7 +2645,7 @@ static int sdebug_add_adapter(void) struct sdebug_dev_info *sdbg_devinfo; struct list_head *lh, *lh_sf; - sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); + sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { printk(KERN_ERR "%s: out of memory at line %d\n", @@ -1824,7 +2657,7 @@ static int sdebug_add_adapter(void) devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; for (k = 0; k < devs_per_host; k++) { - sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo), GFP_KERNEL); + sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); if (NULL == sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); @@ -1905,7 +2738,7 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { @@ -1959,7 +2792,7 @@ static void sdebug_max_tgts_luns(void) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ } spin_unlock(&sdebug_host_list_lock); } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index fb5cb4c9ac6..3d0429bc14a 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -162,7 +162,7 @@ static struct { {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ + {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6a7a60fc0a4..6683d596234 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1672,7 +1672,9 @@ int scsi_reset_provider(struct scsi_device *dev, int flag) { struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); + struct Scsi_Host *shost = dev->host; struct request req; + unsigned long flags; int rtn; scmd->request = &req; @@ -1699,6 +1701,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag) */ scmd->pid = 0; + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 1; + spin_unlock_irqrestore(shost->host_lock, flags); + switch (flag) { case SCSI_TRY_RESET_DEVICE: rtn = scsi_try_bus_device_reset(scmd); @@ -1717,6 +1723,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag) rtn = FAILED; } + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 0; + spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * be sure to wake up anyone who was sleeping or had their queue + * suspended while we performed the TMF. + */ + SCSI_LOG_ERROR_RECOVERY(3, + printk("%s: waking up host to restart after TMF\n", + __FUNCTION__)); + + wake_up(&shost->host_wait); + + scsi_run_host_queues(shost); + scsi_next_command(scmd); return rtn; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3d04a9f386a..08af9aae7df 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -855,8 +855,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) * b) We can just use scsi_requeue_command() here. This would * be used if we just wanted to retry, for example. */ -void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, - unsigned int block_bytes) +void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; int this_count = cmd->bufflen; @@ -921,87 +920,70 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, * Next deal with any sectors which we were able to correctly * handle. */ - if (good_bytes >= 0) { - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n", - req->nr_sectors, good_bytes)); - SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + "%d bytes done.\n", + req->nr_sectors, good_bytes)); + SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); - if (clear_errors) - req->errors = 0; - /* - * If multiple sectors are requested in one buffer, then - * they will have been finished off by the first command. - * If not, then we have a multi-buffer command. - * - * If block_bytes != 0, it means we had a medium error - * of some sort, and that we want to mark some number of - * sectors as not uptodate. Thus we want to inhibit - * requeueing right here - we will requeue down below - * when we handle the bad sectors. - */ + if (clear_errors) + req->errors = 0; - /* - * If the command completed without error, then either - * finish off the rest of the command, or start a new one. - */ - if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) - return; - } - /* - * Now, if we were good little boys and girls, Santa left us a request - * sense buffer. We can extract information from this, so we - * can choose a block to remap, etc. + /* A number of bytes were successfully read. If there + * are leftovers and there is some kind of error + * (result != 0), retry the rest. + */ + if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) + return; + + /* good_bytes = 0, or (inclusive) there were leftovers and + * result = 0, so scsi_end_request couldn't retry. */ if (sense_valid && !sense_deferred) { switch (sshdr.sense_key) { case UNIT_ATTENTION: if (cmd->device->removable) { - /* detected disc change. set a bit + /* Detected disc change. Set a bit * and quietly refuse further access. */ cmd->device->changed = 1; - scsi_end_request(cmd, 0, - this_count, 1); + scsi_end_request(cmd, 0, this_count, 1); return; } else { - /* - * Must have been a power glitch, or a - * bus reset. Could not have been a - * media change, so we just retry the - * request and see what happens. - */ + /* Must have been a power glitch, or a + * bus reset. Could not have been a + * media change, so we just retry the + * request and see what happens. + */ scsi_requeue_command(q, cmd); return; } break; case ILLEGAL_REQUEST: - /* - * If we had an ILLEGAL REQUEST returned, then we may - * have performed an unsupported command. The only - * thing this should be would be a ten byte read where - * only a six byte read was supported. Also, on a - * system where READ CAPACITY failed, we may have read - * past the end of the disk. - */ + /* If we had an ILLEGAL REQUEST returned, then + * we may have performed an unsupported + * command. The only thing this should be + * would be a ten byte read where only a six + * byte read was supported. Also, on a system + * where READ CAPACITY failed, we may have + * read past the end of the disk. + */ if ((cmd->device->use_10_for_rw && sshdr.asc == 0x20 && sshdr.ascq == 0x00) && (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == WRITE_10)) { cmd->device->use_10_for_rw = 0; - /* - * This will cause a retry with a 6-byte - * command. + /* This will cause a retry with a + * 6-byte command. */ scsi_requeue_command(q, cmd); - result = 0; + return; } else { scsi_end_request(cmd, 0, this_count, 1); return; } break; case NOT_READY: - /* - * If the device is in the process of becoming + /* If the device is in the process of becoming * ready, or has a temporary blockage, retry. */ if (sshdr.asc == 0x04) { @@ -1021,7 +1003,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, } if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready: "); + "Device not ready: "); scsi_print_sense_hdr("", &sshdr); } scsi_end_request(cmd, 0, this_count, 1); @@ -1029,21 +1011,21 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, case VOLUME_OVERFLOW: if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Volume overflow, CDB: "); + "Volume overflow, CDB: "); __scsi_print_command(cmd->data_cmnd); scsi_print_sense("", cmd); } - scsi_end_request(cmd, 0, block_bytes, 1); + /* See SSC3rXX or current. */ + scsi_end_request(cmd, 0, this_count, 1); return; default: break; } - } /* driver byte != 0 */ + } if (host_byte(result) == DID_RESET) { - /* - * Third party bus reset or reset for error - * recovery reasons. Just retry the request - * and see what happens. + /* Third party bus reset or reset for error recovery + * reasons. Just retry the request and see what + * happens. */ scsi_requeue_command(q, cmd); return; @@ -1051,21 +1033,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, if (result) { if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "SCSI error: return code = 0x%x\n", result); - + "SCSI error: return code = 0x%08x\n", + result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - /* - * Mark a single buffer as not uptodate. Queue the remainder. - * We sometimes get this cruft in the event that a medium error - * isn't properly reported. - */ - block_bytes = req->hard_cur_sectors << 9; - if (!block_bytes) - block_bytes = req->data_len; - scsi_end_request(cmd, 0, block_bytes, 1); } + scsi_end_request(cmd, 0, this_count, !result); } EXPORT_SYMBOL(scsi_io_completion); @@ -1169,7 +1143,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd) * successfully. Since this is a REQ_BLOCK_PC command the * caller should check the request's errors value */ - scsi_io_completion(cmd, cmd->bufflen, 0); + scsi_io_completion(cmd, cmd->bufflen); } static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd) @@ -2050,6 +2024,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) switch (oldstate) { case SDEV_CREATED: case SDEV_RUNNING: + case SDEV_QUIESCE: case SDEV_OFFLINE: case SDEV_BLOCK: break; @@ -2060,6 +2035,9 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) case SDEV_DEL: switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + case SDEV_OFFLINE: case SDEV_CANCEL: break; default: diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 015c90cf3ab..e2fbe9a9d5a 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -116,7 +116,7 @@ extern struct bus_type scsi_bus_type; * classes. */ -#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT (HZ*60) +#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */ extern int scsi_internal_device_block(struct scsi_device *sdev); extern int scsi_internal_device_unblock(struct scsi_device *sdev); diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index d76e6e3d8ca..e1edab45a37 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h @@ -2,7 +2,8 @@ #define _SCSI_SAS_INTERNAL_H #define SAS_HOST_ATTRS 0 -#define SAS_PORT_ATTRS 17 +#define SAS_PHY_ATTRS 17 +#define SAS_PORT_ATTRS 1 #define SAS_RPORT_ATTRS 7 #define SAS_END_DEV_ATTRS 3 #define SAS_EXPANDER_ATTRS 7 @@ -13,12 +14,14 @@ struct sas_internal { struct sas_domain_function_template *dft; struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; - struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; + struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS]; + struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS]; struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; struct transport_container phy_attr_cont; + struct transport_container port_attr_cont; struct transport_container rphy_attr_cont; struct transport_container end_dev_attr_cont; struct transport_container expander_attr_cont; @@ -28,7 +31,8 @@ struct sas_internal { * needed by scsi_sysfs.c */ struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; - struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; + struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1]; + struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1]; struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1341608e9e3..1bd92b9b46d 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -809,6 +809,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) static inline void scsi_destroy_sdev(struct scsi_device *sdev) { + scsi_device_set_state(sdev, SDEV_DEL); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(&sdev->sdev_gendev); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index f2db7a41cf1..b03aa85108e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -368,7 +368,7 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class, * should insulate the loss of a remote port. * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. */ -static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT; +static unsigned int fc_dev_loss_tmo = 60; /* seconds */ module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dev_loss_tmo, @@ -1284,7 +1284,9 @@ EXPORT_SYMBOL(fc_release_transport); * @work: Work to queue for execution. * * Return value: - * 0 on success / != 0 for error + * 1 - work queued for execution + * 0 - work is already queued + * -EINVAL - work queue doesn't exist **/ static int fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) @@ -1434,8 +1436,6 @@ fc_starget_delete(void *data) struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; - scsi_target_unblock(&rport->dev); - spin_lock_irqsave(shost->host_lock, flags); if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { spin_unlock_irqrestore(shost->host_lock, flags); @@ -1476,7 +1476,8 @@ fc_rport_final_delete(void *data) transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ + put_device(dev); /* for self-reference */ } @@ -1537,13 +1538,13 @@ fc_rport_create(struct Scsi_Host *shost, int channel, else rport->scsi_target_id = -1; list_add_tail(&rport->peers, &fc_host->rports); - get_device(&shost->shost_gendev); + get_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); dev = &rport->dev; - device_initialize(dev); - dev->parent = get_device(&shost->shost_gendev); + device_initialize(dev); /* takes self reference */ + dev->parent = get_device(&shost->shost_gendev); /* parent reference */ dev->release = fc_rport_dev_release; sprintf(dev->bus_id, "rport-%d:%d-%d", shost->host_no, channel, rport->number); @@ -1567,10 +1568,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel, delete_rport: transport_destroy_device(dev); - put_device(dev->parent); spin_lock_irqsave(shost->host_lock, flags); list_del(&rport->peers); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); put_device(dev->parent); kfree(rport); @@ -1707,6 +1707,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + return rport; } } @@ -1762,9 +1764,10 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, /* initiate a scan of the target */ rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); - } - - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + } else + spin_unlock_irqrestore(shost->host_lock, flags); return rport; } @@ -1938,6 +1941,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); } } EXPORT_SYMBOL(fc_remote_port_rolechg); @@ -1970,8 +1974,9 @@ fc_timeout_deleted_rport(void *data) dev_printk(KERN_ERR, &rport->dev, "blocked FC remote port time out: no longer" " a FCP target, removing starget\n"); - fc_queue_work(shost, &rport->stgt_delete_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); return; } @@ -2035,17 +2040,15 @@ fc_timeout_deleted_rport(void *data) * went away and didn't come back - we'll remove * all attached scsi devices. */ - fc_queue_work(shost, &rport->stgt_delete_work); - spin_unlock_irqrestore(shost->host_lock, flags); + + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); } /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. * - * Will unblock the target (in case it went away and has now come back), - * then invoke a scan. - * * @data: remote port to be scanned. **/ static void @@ -2057,7 +2060,6 @@ fc_scsi_scan_rport(void *data) if ((rport->port_state == FC_PORTSTATE_ONLINE) && (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { - scsi_target_unblock(&rport->dev); scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, SCAN_WILD_CARD, 1); } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 5569fdcfd62..7b9e8fa1a4e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -228,14 +228,11 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); - struct iscsi_transport *transport = session->transport; struct Scsi_Host *shost; shost = iscsi_session_to_shost(session); scsi_host_put(shost); - kfree(session->targetname); kfree(session); - module_put(transport->owner); } static int iscsi_is_session_dev(const struct device *dev) @@ -251,10 +248,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&ihost->mutex); list_for_each_entry(session, &ihost->sessions, host_list) { - if ((channel == SCAN_WILD_CARD || - channel == session->channel) && + if ((channel == SCAN_WILD_CARD || channel == 0) && (id == SCAN_WILD_CARD || id == session->target_id)) - scsi_scan_target(&session->dev, session->channel, + scsi_scan_target(&session->dev, 0, session->target_id, lun, 1); } mutex_unlock(&ihost->mutex); @@ -291,80 +287,92 @@ void iscsi_block_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_block_session); -/** - * iscsi_create_session - create iscsi class session - * @shost: scsi host - * @transport: iscsi transport - * - * This can be called from a LLD or iscsi_transport. - **/ struct iscsi_cls_session * -iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *transport, int channel) +iscsi_alloc_session(struct Scsi_Host *shost, + struct iscsi_transport *transport) { - struct iscsi_host *ihost; struct iscsi_cls_session *session; - int err; - - if (!try_module_get(transport->owner)) - return NULL; session = kzalloc(sizeof(*session) + transport->sessiondata_size, GFP_KERNEL); if (!session) - goto module_put; + return NULL; + session->transport = transport; session->recovery_tmo = 120; INIT_WORK(&session->recovery_work, session_recovery_timedout, session); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + /* this is released in the dev's release function */ + scsi_host_get(shost); + session->dev.parent = &shost->shost_gendev; + session->dev.release = iscsi_session_release; + device_initialize(&session->dev); if (transport->sessiondata_size) session->dd_data = &session[1]; + return session; +} +EXPORT_SYMBOL_GPL(iscsi_alloc_session); - /* this is released in the dev's release function */ - scsi_host_get(shost); - ihost = shost->shost_data; +int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost; + int err; + ihost = shost->shost_data; session->sid = iscsi_session_nr++; - session->channel = channel; - session->target_id = ihost->next_target_id++; + session->target_id = target_id; snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid); - session->dev.parent = &shost->shost_gendev; - session->dev.release = iscsi_session_release; - err = device_register(&session->dev); + err = device_add(&session->dev); if (err) { dev_printk(KERN_ERR, &session->dev, "iscsi: could not " "register session's dev\n"); - goto free_session; + goto release_host; } transport_register_device(&session->dev); mutex_lock(&ihost->mutex); list_add(&session->host_list, &ihost->sessions); mutex_unlock(&ihost->mutex); + return 0; - return session; - -free_session: - kfree(session); -module_put: - module_put(transport->owner); - return NULL; +release_host: + scsi_host_put(shost); + return err; } - -EXPORT_SYMBOL_GPL(iscsi_create_session); +EXPORT_SYMBOL_GPL(iscsi_add_session); /** - * iscsi_destroy_session - destroy iscsi session - * @session: iscsi_session + * iscsi_create_session - create iscsi class session + * @shost: scsi host + * @transport: iscsi transport * - * Can be called by a LLD or iscsi_transport. There must not be - * any running connections. + * This can be called from a LLD or iscsi_transport. **/ -int iscsi_destroy_session(struct iscsi_cls_session *session) +struct iscsi_cls_session * +iscsi_create_session(struct Scsi_Host *shost, + struct iscsi_transport *transport, + unsigned int target_id) +{ + struct iscsi_cls_session *session; + + session = iscsi_alloc_session(shost, transport); + if (!session) + return NULL; + + if (iscsi_add_session(session, target_id)) { + iscsi_free_session(session); + return NULL; + } + return session; +} +EXPORT_SYMBOL_GPL(iscsi_create_session); + +void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; @@ -376,19 +384,88 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) list_del(&session->host_list); mutex_unlock(&ihost->mutex); + scsi_remove_target(&session->dev); + transport_unregister_device(&session->dev); - device_unregister(&session->dev); - return 0; + device_del(&session->dev); +} +EXPORT_SYMBOL_GPL(iscsi_remove_session); + +void iscsi_free_session(struct iscsi_cls_session *session) +{ + put_device(&session->dev); } +EXPORT_SYMBOL_GPL(iscsi_free_session); + +/** + * iscsi_destroy_session - destroy iscsi session + * @session: iscsi_session + * + * Can be called by a LLD or iscsi_transport. There must not be + * any running connections. + **/ +int iscsi_destroy_session(struct iscsi_cls_session *session) +{ + iscsi_remove_session(session); + iscsi_free_session(session); + return 0; +} EXPORT_SYMBOL_GPL(iscsi_destroy_session); +static void mempool_zone_destroy(struct mempool_zone *zp) +{ + mempool_destroy(zp->pool); + kfree(zp); +} + +static void* +mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) +{ + struct mempool_zone *zone = pool_data; + + return alloc_skb(zone->size, gfp_mask); +} + +static void +mempool_zone_free_skb(void *element, void *pool_data) +{ + kfree_skb(element); +} + +static struct mempool_zone * +mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) +{ + struct mempool_zone *zp; + + zp = kzalloc(sizeof(*zp), GFP_KERNEL); + if (!zp) + return NULL; + + zp->size = size; + zp->hiwat = hiwat; + INIT_LIST_HEAD(&zp->freequeue); + spin_lock_init(&zp->freelock); + atomic_set(&zp->allocated, 0); + + zp->pool = mempool_create(max, mempool_zone_alloc_skb, + mempool_zone_free_skb, zp); + if (!zp->pool) { + kfree(zp); + return NULL; + } + + return zp; +} + static void iscsi_conn_release(struct device *dev) { struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; - kfree(conn->persistent_address); + mempool_zone_destroy(conn->z_pdu); + mempool_zone_destroy(conn->z_error); + kfree(conn); put_device(parent); } @@ -398,6 +475,31 @@ static int iscsi_is_conn_dev(const struct device *dev) return dev->release == iscsi_conn_release; } +static int iscsi_create_event_pools(struct iscsi_cls_conn *conn) +{ + conn->z_pdu = mempool_zone_init(Z_MAX_PDU, + NLMSG_SPACE(sizeof(struct iscsi_uevent) + + sizeof(struct iscsi_hdr) + + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), + Z_HIWAT_PDU); + if (!conn->z_pdu) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "pdu zone for new conn\n"); + return -ENOMEM; + } + + conn->z_error = mempool_zone_init(Z_MAX_ERROR, + NLMSG_SPACE(sizeof(struct iscsi_uevent)), + Z_HIWAT_ERROR); + if (!conn->z_error) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "error zone for new conn\n"); + mempool_zone_destroy(conn->z_pdu); + return -ENOMEM; + } + return 0; +} + /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session @@ -430,9 +532,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->transport = transport; conn->cid = cid; + if (iscsi_create_event_pools(conn)) + goto free_conn; + /* this is released in the dev's release function */ if (!get_device(&session->dev)) - goto free_conn; + goto free_conn_pools; snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", session->sid, cid); @@ -449,6 +554,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) release_parent_ref: put_device(&session->dev); +free_conn_pools: + free_conn: kfree(conn); return NULL; @@ -496,20 +603,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb) return (struct list_head *)&skb->cb; } -static void* -mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) -{ - struct mempool_zone *zone = pool_data; - - return alloc_skb(zone->size, gfp_mask); -} - -static void -mempool_zone_free_skb(void *element, void *pool_data) -{ - kfree_skb(element); -} - static void mempool_zone_complete(struct mempool_zone *zone) { @@ -529,37 +622,6 @@ mempool_zone_complete(struct mempool_zone *zone) spin_unlock_irqrestore(&zone->freelock, flags); } -static struct mempool_zone * -mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) -{ - struct mempool_zone *zp; - - zp = kzalloc(sizeof(*zp), GFP_KERNEL); - if (!zp) - return NULL; - - zp->size = size; - zp->hiwat = hiwat; - INIT_LIST_HEAD(&zp->freequeue); - spin_lock_init(&zp->freelock); - atomic_set(&zp->allocated, 0); - - zp->pool = mempool_create(max, mempool_zone_alloc_skb, - mempool_zone_free_skb, zp); - if (!zp->pool) { - kfree(zp); - return NULL; - } - - return zp; -} - -static void mempool_zone_destroy(struct mempool_zone *zp) -{ - mempool_destroy(zp->pool); - kfree(zp); -} - static struct sk_buff* mempool_zone_get_skb(struct mempool_zone *zone) { @@ -572,6 +634,27 @@ mempool_zone_get_skb(struct mempool_zone *zone) } static int +iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb) +{ + unsigned long flags; + int rc; + + skb_get(skb); + rc = netlink_broadcast(nls, skb, 0, 1, GFP_KERNEL); + if (rc < 0) { + mempool_free(skb, zone->pool); + printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); + return rc; + } + + spin_lock_irqsave(&zone->freelock, flags); + INIT_LIST_HEAD(skb_to_lh(skb)); + list_add(skb_to_lh(skb), &zone->freequeue); + spin_unlock_irqrestore(&zone->freelock, flags); + return 0; +} + +static int iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) { unsigned long flags; @@ -666,7 +749,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid); + iscsi_broadcast_skb(conn->z_error, skb); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error); @@ -767,6 +850,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return err; } +/** + * iscsi_if_destroy_session_done - send session destr. completion event + * @conn: last connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * removed a session. + **/ +int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_KEVENT_DESTROY_SESSION; + ev->r.d_session.host_no = shost->host_no; + ev->r.d_session.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session destruction event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + conn->active = 0; + list_del(&conn->conn_list); + spin_unlock_irqrestore(&connlock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done); + +/** + * iscsi_if_create_session_done - send session creation completion event + * @conn: leading connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * created a session or a existing session is back in the logged in state. + **/ +int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_UEVENT_CREATE_SESSION; + ev->r.c_session_ret.host_no = shost->host_no; + ev->r.c_session_ret.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_add(&session->sess_list, &sesslist); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + list_add(&conn->conn_list, &connlist); + conn->active = 1; + spin_unlock_irqrestore(&connlock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); + static int iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { @@ -812,26 +1020,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) return -ENOMEM; } - conn->z_pdu = mempool_zone_init(Z_MAX_PDU, - NLMSG_SPACE(sizeof(struct iscsi_uevent) + - sizeof(struct iscsi_hdr) + - DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), - Z_HIWAT_PDU); - if (!conn->z_pdu) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "pdu zone for new conn\n"); - goto destroy_conn; - } - - conn->z_error = mempool_zone_init(Z_MAX_ERROR, - NLMSG_SPACE(sizeof(struct iscsi_uevent)), - Z_HIWAT_ERROR); - if (!conn->z_error) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "error zone for new conn\n"); - goto free_pdu_pool; - } - ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; @@ -841,13 +1029,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) spin_unlock_irqrestore(&connlock, flags); return 0; - -free_pdu_pool: - mempool_zone_destroy(conn->z_pdu); -destroy_conn: - if (transport->destroy_conn) - transport->destroy_conn(conn->dd_data); - return -ENOMEM; } static int @@ -855,7 +1036,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev { unsigned long flags; struct iscsi_cls_conn *conn; - struct mempool_zone *z_error, *z_pdu; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) @@ -865,35 +1045,18 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev list_del(&conn->conn_list); spin_unlock_irqrestore(&connlock, flags); - z_pdu = conn->z_pdu; - z_error = conn->z_error; - if (transport->destroy_conn) transport->destroy_conn(conn); - - mempool_zone_destroy(z_pdu); - mempool_zone_destroy(z_error); - return 0; } -static void -iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data) -{ - if (ev->u.set_param.len != sizeof(uint32_t)) - BUG(); - memcpy(value, data, min_t(uint32_t, sizeof(uint32_t), - ev->u.set_param.len)); -} - static int iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) { char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; - int err = 0; - uint32_t value = 0; + int err = 0, value = 0; session = iscsi_session_lookup(ev->u.set_param.sid); conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); @@ -902,42 +1065,13 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: - iscsi_copy_param(ev, &value, data); + sscanf(data, "%d", &value); if (value != 0) session->recovery_tmo = value; break; - case ISCSI_PARAM_TARGET_NAME: - /* this should not change between logins */ - if (session->targetname) - return 0; - - session->targetname = kstrdup(data, GFP_KERNEL); - if (!session->targetname) - return -ENOMEM; - break; - case ISCSI_PARAM_TPGT: - iscsi_copy_param(ev, &value, data); - session->tpgt = value; - break; - case ISCSI_PARAM_PERSISTENT_PORT: - iscsi_copy_param(ev, &value, data); - conn->persistent_port = value; - break; - case ISCSI_PARAM_PERSISTENT_ADDRESS: - /* - * this is the address returned in discovery so it should - * not change between logins. - */ - if (conn->persistent_address) - return 0; - - conn->persistent_address = kstrdup(data, GFP_KERNEL); - if (!conn->persistent_address) - return -ENOMEM; - break; default: - iscsi_copy_param(ev, &value, data); - err = transport->set_param(conn, ev->u.set_param.param, value); + err = transport->set_param(conn, ev->u.set_param.param, + data, ev->u.set_param.len); } return err; @@ -978,6 +1112,21 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, } static int +iscsi_tgt_dscvr(struct iscsi_transport *transport, + struct iscsi_uevent *ev) +{ + struct sockaddr *dst_addr; + + if (!transport->tgt_dscvr) + return -EINVAL; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + return transport->tgt_dscvr(ev->u.tgt_dscvr.type, + ev->u.tgt_dscvr.host_no, + ev->u.tgt_dscvr.enable, dst_addr); +} + +static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { int err = 0; @@ -1065,6 +1214,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); break; + case ISCSI_UEVENT_TGT_DSCVR: + err = iscsi_tgt_dscvr(transport, ev); + break; default: err = -EINVAL; break; @@ -1147,49 +1299,31 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name = \ /* * iSCSI connection attrs */ -#define iscsi_conn_int_attr_show(param, format) \ -static ssize_t \ -show_conn_int_param_##param(struct class_device *cdev, char *buf) \ -{ \ - uint32_t value = 0; \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - struct iscsi_transport *t = conn->transport; \ - \ - t->get_conn_param(conn, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ -} - -#define iscsi_conn_int_attr(field, param, format) \ - iscsi_conn_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \ - NULL); - -iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); -iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); -iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d"); -iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); -iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); -iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); -iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); -iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); -iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u"); - -#define iscsi_conn_str_attr_show(param) \ +#define iscsi_conn_attr_show(param) \ static ssize_t \ -show_conn_str_param_##param(struct class_device *cdev, char *buf) \ +show_conn_param_##param(struct class_device *cdev, char *buf) \ { \ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ struct iscsi_transport *t = conn->transport; \ - return t->get_conn_str_param(conn, param, buf); \ + return t->get_conn_param(conn, param, buf); \ } -#define iscsi_conn_str_attr(field, param) \ - iscsi_conn_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \ +#define iscsi_conn_attr(field, param) \ + iscsi_conn_attr_show(param) \ +static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \ NULL); -iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); -iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); +iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); +iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); +iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN); +iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN); +iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN); +iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN); +iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT); +iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); +iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); +iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); +iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1197,61 +1331,36 @@ iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); /* * iSCSI session attrs */ -#define iscsi_session_int_attr_show(param, format) \ -static ssize_t \ -show_session_int_param_##param(struct class_device *cdev, char *buf) \ -{ \ - uint32_t value = 0; \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ - struct iscsi_transport *t = session->transport; \ - \ - t->get_session_param(session, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ -} - -#define iscsi_session_int_attr(field, param, format) \ - iscsi_session_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \ - NULL); - -iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); -iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); -iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d"); -iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u"); -iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u"); -iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); -iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); -iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); -iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d"); - -#define iscsi_session_str_attr_show(param) \ +#define iscsi_session_attr_show(param) \ static ssize_t \ -show_session_str_param_##param(struct class_device *cdev, char *buf) \ +show_session_param_##param(struct class_device *cdev, char *buf) \ { \ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ struct iscsi_transport *t = session->transport; \ - return t->get_session_str_param(session, param, buf); \ + return t->get_session_param(session, param, buf); \ } -#define iscsi_session_str_attr(field, param) \ - iscsi_session_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \ +#define iscsi_session_attr(field, param) \ + iscsi_session_attr_show(param) \ +static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \ NULL); -iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); +iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); +iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN); +iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST); +iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST); +iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); +iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN); +iscsi_session_attr(erl, ISCSI_PARAM_ERL); +iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT); -/* - * Private session and conn attrs. userspace uses several iscsi values - * to identify each session between reboots. Some of these values may not - * be present in the iscsi_transport/LLD driver becuase userspace handles - * login (and failback for login redirect) so for these type of drivers - * the class manages the attrs and values for the iscsi_transport/LLD - */ #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ -show_priv_session_##field(struct class_device *cdev, char *buf) \ +show_priv_session_##field(struct class_device *cdev, char *buf) \ { \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\ return sprintf(buf, format"\n", session->field); \ } @@ -1259,31 +1368,15 @@ show_priv_session_##field(struct class_device *cdev, char *buf) \ iscsi_priv_session_attr_show(field, format) \ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ NULL) -iscsi_priv_session_attr(targetname, "%s"); -iscsi_priv_session_attr(tpgt, "%d"); iscsi_priv_session_attr(recovery_tmo, "%d"); -#define iscsi_priv_conn_attr_show(field, format) \ -static ssize_t \ -show_priv_conn_##field(struct class_device *cdev, char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - return sprintf(buf, format"\n", conn->field); \ -} - -#define iscsi_priv_conn_attr(field, format) \ - iscsi_priv_conn_attr_show(field, format) \ -static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \ - NULL) -iscsi_priv_conn_attr(persistent_address, "%s"); -iscsi_priv_conn_attr(persistent_port, "%d"); - #define SETUP_PRIV_SESSION_RD_ATTR(field) \ do { \ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ count++; \ } while (0) + #define SETUP_SESSION_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1292,12 +1385,6 @@ do { \ } \ } while (0) -#define SETUP_PRIV_CONN_RD_ATTR(field) \ -do { \ - priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \ - count++; \ -} while (0) - #define SETUP_CONN_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1388,6 +1475,7 @@ iscsi_register_transport(struct iscsi_transport *tt) if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); + priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; @@ -1424,16 +1512,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); - - if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) - SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_address); - - if (tt->param_mask & ISCSI_PERSISTENT_PORT) - SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_port); + SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); + SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; @@ -1453,18 +1533,10 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); + SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); + SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); - if (tt->param_mask & ISCSI_TARGET_NAME) - SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); - else - SETUP_PRIV_SESSION_RD_ATTR(targetname); - - if (tt->param_mask & ISCSI_TPGT) - SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); - else - SETUP_PRIV_SESSION_RD_ATTR(tpgt); - BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 1fe6b2d0185..dd075627e60 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -174,12 +174,29 @@ static int sas_host_match(struct attribute_container *cont, static int do_sas_phy_delete(struct device *dev, void *data) { - if (scsi_is_sas_phy(dev)) + int pass = (int)(unsigned long)data; + + if (pass == 0 && scsi_is_sas_port(dev)) + sas_port_delete(dev_to_sas_port(dev)); + else if (pass == 1 && scsi_is_sas_phy(dev)) sas_phy_delete(dev_to_phy(dev)); return 0; } /** + * sas_remove_children -- tear down a devices SAS data structures + * @dev: device belonging to the sas object + * + * Removes all SAS PHYs and remote PHYs for a given object + */ +void sas_remove_children(struct device *dev) +{ + device_for_each_child(dev, (void *)0, do_sas_phy_delete); + device_for_each_child(dev, (void *)1, do_sas_phy_delete); +} +EXPORT_SYMBOL(sas_remove_children); + +/** * sas_remove_host -- tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down * @@ -188,13 +205,13 @@ static int do_sas_phy_delete(struct device *dev, void *data) */ void sas_remove_host(struct Scsi_Host *shost) { - device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); + sas_remove_children(&shost->shost_gendev); } EXPORT_SYMBOL(sas_remove_host); /* - * SAS Port attributes + * SAS Phy attributes */ #define sas_phy_show_simple(field, name, format_string, cast) \ @@ -310,7 +327,7 @@ sas_phy_protocol_attr(identify.target_port_protocols, sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", unsigned long long); sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); -sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); +//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); sas_phy_linkspeed_attr(negotiated_linkrate); sas_phy_linkspeed_attr(minimum_linkrate_hw); sas_phy_linkspeed_attr(minimum_linkrate); @@ -378,9 +395,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) device_initialize(&phy->dev); phy->dev.parent = get_device(parent); phy->dev.release = sas_phy_release; + INIT_LIST_HEAD(&phy->port_siblings); if (scsi_is_sas_expander_device(parent)) { struct sas_rphy *rphy = dev_to_rphy(parent); - sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no, + sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, rphy->scsi_target_id, number); } else sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); @@ -440,8 +458,8 @@ sas_phy_delete(struct sas_phy *phy) { struct device *dev = &phy->dev; - if (phy->rphy) - sas_rphy_delete(phy->rphy); + /* this happens if the phy is still part of a port when deleted */ + BUG_ON(!list_empty(&phy->port_siblings)); transport_remove_device(dev); device_del(dev); @@ -464,6 +482,258 @@ int scsi_is_sas_phy(const struct device *dev) EXPORT_SYMBOL(scsi_is_sas_phy); /* + * SAS Port attributes + */ +#define sas_port_show_simple(field, name, format_string, cast) \ +static ssize_t \ +show_sas_port_##name(struct class_device *cdev, char *buf) \ +{ \ + struct sas_port *port = transport_class_to_sas_port(cdev); \ + \ + return snprintf(buf, 20, format_string, cast port->field); \ +} + +#define sas_port_simple_attr(field, name, format_string, type) \ + sas_port_show_simple(field, name, format_string, (type)) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) + +sas_port_simple_attr(num_phys, num_phys, "%d\n", int); + +static DECLARE_TRANSPORT_CLASS(sas_port_class, + "sas_port", NULL, NULL, NULL); + +static int sas_port_match(struct attribute_container *cont, struct device *dev) +{ + struct Scsi_Host *shost; + struct sas_internal *i; + + if (!scsi_is_sas_port(dev)) + return 0; + shost = dev_to_shost(dev->parent); + + if (!shost->transportt) + return 0; + if (shost->transportt->host_attrs.ac.class != + &sas_host_class.class) + return 0; + + i = to_sas_internal(shost->transportt); + return &i->port_attr_cont.ac == cont; +} + + +static void sas_port_release(struct device *dev) +{ + struct sas_port *port = dev_to_sas_port(dev); + + BUG_ON(!list_empty(&port->phy_list)); + + put_device(dev->parent); + kfree(port); +} + +static void sas_port_create_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id); + sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); +} + +static void sas_port_delete_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); + sysfs_remove_link(&phy->dev.kobj, "port"); +} + +/** sas_port_alloc - allocate and initialize a SAS port structure + * + * @parent: parent device + * @port_id: port number + * + * Allocates a SAS port structure. It will be added to the device tree + * below the device specified by @parent which must be either a Scsi_Host + * or a sas_expander_device. + * + * Returns %NULL on error + */ +struct sas_port *sas_port_alloc(struct device *parent, int port_id) +{ + struct Scsi_Host *shost = dev_to_shost(parent); + struct sas_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return NULL; + + port->port_identifier = port_id; + + device_initialize(&port->dev); + + port->dev.parent = get_device(parent); + port->dev.release = sas_port_release; + + mutex_init(&port->phy_list_mutex); + INIT_LIST_HEAD(&port->phy_list); + + if (scsi_is_sas_expander_device(parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent); + sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, + rphy->scsi_target_id, port->port_identifier); + } else + sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, + port->port_identifier); + + transport_setup_device(&port->dev); + + return port; +} +EXPORT_SYMBOL(sas_port_alloc); + +/** + * sas_port_add - add a SAS port to the device hierarchy + * + * @port: port to be added + * + * publishes a port to the rest of the system + */ +int sas_port_add(struct sas_port *port) +{ + int error; + + /* No phys should be added until this is made visible */ + BUG_ON(!list_empty(&port->phy_list)); + + error = device_add(&port->dev); + + if (error) + return error; + + transport_add_device(&port->dev); + transport_configure_device(&port->dev); + + return 0; +} +EXPORT_SYMBOL(sas_port_add); + +/** + * sas_port_free -- free a SAS PORT + * @port: SAS PORT to free + * + * Frees the specified SAS PORT. + * + * Note: + * This function must only be called on a PORT that has not + * sucessfully been added using sas_port_add(). + */ +void sas_port_free(struct sas_port *port) +{ + transport_destroy_device(&port->dev); + put_device(&port->dev); +} +EXPORT_SYMBOL(sas_port_free); + +/** + * sas_port_delete -- remove SAS PORT + * @port: SAS PORT to remove + * + * Removes the specified SAS PORT. If the SAS PORT has an + * associated phys, unlink them from the port as well. + */ +void sas_port_delete(struct sas_port *port) +{ + struct device *dev = &port->dev; + struct sas_phy *phy, *tmp_phy; + + if (port->rphy) { + sas_rphy_delete(port->rphy); + port->rphy = NULL; + } + + mutex_lock(&port->phy_list_mutex); + list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, + port_siblings) { + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + } + mutex_unlock(&port->phy_list_mutex); + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} +EXPORT_SYMBOL(sas_port_delete); + +/** + * scsi_is_sas_port -- check if a struct device represents a SAS port + * @dev: device to check + * + * Returns: + * %1 if the device represents a SAS Port, %0 else + */ +int scsi_is_sas_port(const struct device *dev) +{ + return dev->release == sas_port_release; +} +EXPORT_SYMBOL(scsi_is_sas_port); + +/** + * sas_port_add_phy - add another phy to a port to form a wide port + * @port: port to add the phy to + * @phy: phy to add + * + * When a port is initially created, it is empty (has no phys). All + * ports must have at least one phy to operated, and all wide ports + * must have at least two. The current code makes no difference + * between ports and wide ports, but the only object that can be + * connected to a remote device is a port, so ports must be formed on + * all devices with phys if they're connected to anything. + */ +void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + if (unlikely(!list_empty(&phy->port_siblings))) { + /* make sure we're already on this port */ + struct sas_phy *tmp; + + list_for_each_entry(tmp, &port->phy_list, port_siblings) + if (tmp == phy) + break; + /* If this trips, you added a phy that was already + * part of a different port */ + if (unlikely(tmp != phy)) { + dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id); + BUG(); + } + } else { + sas_port_create_link(port, phy); + list_add_tail(&phy->port_siblings, &port->phy_list); + port->num_phys++; + } + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_add_phy); + +/** + * sas_port_delete_phy - remove a phy from a port or wide port + * @port: port to remove the phy from + * @phy: phy to remove + * + * This operation is used for tearing down ports again. It must be + * done to every port or wide port before calling sas_port_delete. + */ +void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + port->num_phys--; + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_delete_phy); + +/* * SAS remote PHY attributes. */ @@ -767,7 +1037,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy) * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) +struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); struct sas_end_device *rdev; @@ -780,8 +1050,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) device_initialize(&rdev->rphy.dev); rdev->rphy.dev.parent = get_device(&parent->dev); rdev->rphy.dev.release = sas_end_device_release; - sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d", - shost->host_no, parent->port_identifier, parent->number); + if (scsi_is_sas_expander_device(parent->dev.parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", + shost->host_no, rphy->scsi_target_id, parent->port_identifier); + } else + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", + shost->host_no, parent->port_identifier); rdev->rphy.identify.device_type = SAS_END_DEVICE; sas_rphy_initialize(&rdev->rphy); transport_setup_device(&rdev->rphy.dev); @@ -798,7 +1073,7 @@ EXPORT_SYMBOL(sas_end_device_alloc); * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, +struct sas_rphy *sas_expander_alloc(struct sas_port *parent, enum sas_device_type type) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); @@ -837,7 +1112,7 @@ EXPORT_SYMBOL(sas_expander_alloc); */ int sas_rphy_add(struct sas_rphy *rphy) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); + struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); struct sas_identify *identify = &rphy->identify; @@ -910,7 +1185,7 @@ void sas_rphy_delete(struct sas_rphy *rphy) { struct device *dev = &rphy->dev; - struct sas_phy *parent = dev_to_phy(dev->parent); + struct sas_port *parent = dev_to_sas_port(dev->parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); @@ -920,7 +1195,7 @@ sas_rphy_delete(struct sas_rphy *rphy) break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: - device_for_each_child(dev, NULL, do_sas_phy_delete); + sas_remove_children(dev); break; default: break; @@ -967,7 +1242,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&sas_host->lock); list_for_each_entry(rphy, &sas_host->rphy_list, list) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); + struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); if (rphy->identify.device_type != SAS_END_DEVICE || rphy->scsi_target_id == -1) @@ -1003,16 +1278,19 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE(field) \ +#define SETUP_PHY_ATTRIBUTE(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ +#define SETUP_PORT_ATTRIBUTE(field) \ + SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) + +#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ +#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ +#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) #define SETUP_END_DEV_ATTRIBUTE(field) \ @@ -1048,6 +1326,11 @@ sas_attach_transport(struct sas_function_template *ft) i->phy_attr_cont.ac.match = sas_phy_match; transport_container_register(&i->phy_attr_cont); + i->port_attr_cont.ac.class = &sas_port_class.class; + i->port_attr_cont.ac.attrs = &i->port_attrs[0]; + i->port_attr_cont.ac.match = sas_port_match; + transport_container_register(&i->port_attr_cont); + i->rphy_attr_cont.ac.class = &sas_rphy_class.class; i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; i->rphy_attr_cont.ac.match = sas_rphy_match; @@ -1066,30 +1349,35 @@ sas_attach_transport(struct sas_function_template *ft) i->f = ft; count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); i->host_attrs[count] = NULL; count = 0; - SETUP_PORT_ATTRIBUTE(initiator_port_protocols); - SETUP_PORT_ATTRIBUTE(target_port_protocols); - SETUP_PORT_ATTRIBUTE(device_type); - SETUP_PORT_ATTRIBUTE(sas_address); - SETUP_PORT_ATTRIBUTE(phy_identifier); - SETUP_PORT_ATTRIBUTE(port_identifier); - SETUP_PORT_ATTRIBUTE(negotiated_linkrate); - SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(minimum_linkrate); - SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(maximum_linkrate); - - SETUP_PORT_ATTRIBUTE(invalid_dword_count); - SETUP_PORT_ATTRIBUTE(running_disparity_error_count); - SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); - SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); + SETUP_PHY_ATTRIBUTE(initiator_port_protocols); + SETUP_PHY_ATTRIBUTE(target_port_protocols); + SETUP_PHY_ATTRIBUTE(device_type); + SETUP_PHY_ATTRIBUTE(sas_address); + SETUP_PHY_ATTRIBUTE(phy_identifier); + //SETUP_PHY_ATTRIBUTE(port_identifier); + SETUP_PHY_ATTRIBUTE(negotiated_linkrate); + SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(minimum_linkrate); + SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(maximum_linkrate); + + SETUP_PHY_ATTRIBUTE(invalid_dword_count); + SETUP_PHY_ATTRIBUTE(running_disparity_error_count); + SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); + SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); i->phy_attrs[count] = NULL; count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); + i->port_attrs[count] = NULL; + + count = 0; SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); SETUP_RPORT_ATTRIBUTE(rphy_device_type); @@ -1131,6 +1419,7 @@ void sas_release_transport(struct scsi_transport_template *t) transport_container_unregister(&i->t.host_attrs); transport_container_unregister(&i->phy_attr_cont); + transport_container_unregister(&i->port_attr_cont); transport_container_unregister(&i->rphy_attr_cont); transport_container_unregister(&i->end_dev_attr_cont); transport_container_unregister(&i->expander_attr_cont); @@ -1149,9 +1438,12 @@ static __init int sas_transport_init(void) error = transport_class_register(&sas_phy_class); if (error) goto out_unregister_transport; - error = transport_class_register(&sas_rphy_class); + error = transport_class_register(&sas_port_class); if (error) goto out_unregister_phy; + error = transport_class_register(&sas_rphy_class); + if (error) + goto out_unregister_port; error = transport_class_register(&sas_end_dev_class); if (error) goto out_unregister_rphy; @@ -1165,6 +1457,8 @@ static __init int sas_transport_init(void) transport_class_unregister(&sas_end_dev_class); out_unregister_rphy: transport_class_unregister(&sas_rphy_class); + out_unregister_port: + transport_class_unregister(&sas_port_class); out_unregister_phy: transport_class_unregister(&sas_phy_class); out_unregister_transport: @@ -1178,6 +1472,7 @@ static void __exit sas_transport_exit(void) { transport_class_unregister(&sas_host_class); transport_class_unregister(&sas_phy_class); + transport_class_unregister(&sas_port_class); transport_class_unregister(&sas_rphy_class); transport_class_unregister(&sas_end_dev_class); transport_class_unregister(&sas_expander_class); diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index b78354fc4b1..cd68a66c7bb 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) { unsigned char *p; + u64 capacity64 = capacity; /* Suppress gcc warning */ int ret; p = scsi_bios_ptable(bdev); @@ -68,7 +69,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) (unsigned int *)ip + 0, (unsigned int *)ip + 1); kfree(p); - if (ret == -1) { + if (ret == -1 && capacity64 < (1ULL << 32)) { /* pick some standard mapping with at most 1024 cylinders, and at most 62 sectors per track - this works up to 7905 MB */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ea38757d12e..3225d31449e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -207,6 +207,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, return count; } +static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + sdp->allow_restart = simple_strtoul(buf, NULL, 10); + + return count; +} + static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(cdev); @@ -222,10 +239,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); } +static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + + return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); +} + static struct class_device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), + __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, + sd_store_allow_restart), __ATTR_NULL, }; @@ -890,11 +916,10 @@ static struct block_device_operations sd_fops = { static void sd_rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->request_bufflen; - int good_bytes = (result == 0 ? this_count : 0); - sector_t block_sectors = 1; - u64 first_err_block; - sector_t error_sector; + unsigned int xfer_size = SCpnt->request_bufflen; + unsigned int good_bytes = result ? 0 : xfer_size; + u64 start_lba = SCpnt->request->sector; + u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; @@ -905,7 +930,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); } - #ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); @@ -915,89 +939,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif - /* - Handle MEDIUM ERRORs that indicate partial success. Since this is a - relatively rare error condition, no care is taken to avoid - unnecessary additional work such as memcpy's that could be avoided. - */ - if (driver_byte(result) != 0 && - sense_valid && !sense_deferred) { - switch (sshdr.sense_key) { - case MEDIUM_ERROR: - if (!blk_fs_request(SCpnt->request)) - break; - info_valid = scsi_get_sense_info_fld( - SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &first_err_block); - /* - * May want to warn and skip if following cast results - * in actual truncation (if sector_t < 64 bits) - */ - error_sector = (sector_t)first_err_block; - if (SCpnt->request->bio != NULL) - block_sectors = bio_sectors(SCpnt->request->bio); - switch (SCpnt->device->sector_size) { - case 1024: - error_sector <<= 1; - if (block_sectors < 2) - block_sectors = 2; - break; - case 2048: - error_sector <<= 2; - if (block_sectors < 4) - block_sectors = 4; - break; - case 4096: - error_sector <<=3; - if (block_sectors < 8) - block_sectors = 8; - break; - case 256: - error_sector >>= 1; - break; - default: - break; - } + if (driver_byte(result) != DRIVER_SENSE && + (!sense_valid || sense_deferred)) + goto out; - error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - SCpnt->request->sector) << 9; - if (good_bytes < 0 || good_bytes >= this_count) - good_bytes = 0; + switch (sshdr.sense_key) { + case HARDWARE_ERROR: + case MEDIUM_ERROR: + if (!blk_fs_request(SCpnt->request)) + goto out; + info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + &bad_lba); + if (!info_valid) + goto out; + if (xfer_size <= SCpnt->device->sector_size) + goto out; + switch (SCpnt->device->sector_size) { + case 256: + start_lba <<= 1; break; - - case RECOVERED_ERROR: /* an error occurred, but it recovered */ - case NO_SENSE: /* LLDD got sense data */ - /* - * Inform the user, but make sure that it's not treated - * as a hard error. - */ - scsi_print_sense("sd", SCpnt); - SCpnt->result = 0; - memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - good_bytes = this_count; + case 512: break; - - case ILLEGAL_REQUEST: - if (SCpnt->device->use_10_for_rw && - (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10)) - SCpnt->device->use_10_for_rw = 0; - if (SCpnt->device->use_10_for_ms && - (SCpnt->cmnd[0] == MODE_SENSE_10 || - SCpnt->cmnd[0] == MODE_SELECT_10)) - SCpnt->device->use_10_for_ms = 0; + case 1024: + start_lba >>= 1; + break; + case 2048: + start_lba >>= 2; + break; + case 4096: + start_lba >>= 3; break; - default: + /* Print something here with limiting frequency. */ + goto out; break; } + /* This computation should always be done in terms of + * the resolution of the device's medium. + */ + good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; + break; + case RECOVERED_ERROR: + case NO_SENSE: + /* Inform the user, but make sure that it's not treated + * as a hard error. + */ + scsi_print_sense("sd", SCpnt); + SCpnt->result = 0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + good_bytes = xfer_size; + break; + case ILLEGAL_REQUEST: + if (SCpnt->device->use_10_for_rw && + (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10)) + SCpnt->device->use_10_for_rw = 0; + if (SCpnt->device->use_10_for_ms && + (SCpnt->cmnd[0] == MODE_SENSE_10 || + SCpnt->cmnd[0] == MODE_SELECT_10)) + SCpnt->device->use_10_for_ms = 0; + break; + default: + break; } - /* - * This calls the generic completion function, now that we know - * how many actual sectors finished, and how many sectors we need - * to say have failed. - */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + out: + scsi_io_completion(SCpnt, good_bytes); } static int media_not_present(struct scsi_disk *sdkp, diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4e607d3065b..65eef33846b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1401,6 +1401,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) Sg_device *sdp = NULL; struct cdev * cdev = NULL; int error, k; + unsigned long iflags; disk = alloc_disk(1); if (!disk) { @@ -1428,7 +1429,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); if (error) - goto out; + goto cdev_add_err; sdp->cdev = cdev; if (sg_sysfs_valid) { @@ -1455,6 +1456,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) return 0; +cdev_add_err: + write_lock_irqsave(&sg_dev_arr_lock, iflags); + kfree(sg_dev_arr[k]); + sg_dev_arr[k] = NULL; + sg_nr_dev--; + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + out: put_disk(disk); if (cdev) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index ebf6579ed69..fd94408577e 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) * how many actual sectors finished, and how many sectors we need * to say have failed. */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + scsi_io_completion(SCpnt, good_bytes); } static int sr_init_command(struct scsi_cmnd * SCpnt) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b5218fc0ac8..756ceb93ddc 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3599,7 +3599,6 @@ static struct st_buffer * tb->use_sg = max_sg; tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); - tb->in_use = 1; tb->dma = need_dma; tb->buffer_size = got; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 411209048d7..05a5cae126e 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -31,7 +31,6 @@ struct st_request { /* The tape buffer descriptor. */ struct st_buffer { - unsigned char in_use; unsigned char dma; /* DMA-able buffer */ unsigned char do_dio; /* direct i/o set up? */ int buffer_size; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 253797c6009..55ebf035e62 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -47,10 +47,19 @@ enum iscsi_uevent_e { ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13, ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14, + ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, + /* up events */ ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, + ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4, +}; + +enum iscsi_tgt_dscvr { + ISCSI_TGT_DSCVR_SEND_TARGETS = 1, + ISCSI_TGT_DSCVR_ISNS = 2, + ISCSI_TGT_DSCVR_SLP = 3, }; struct iscsi_uevent { @@ -116,6 +125,17 @@ struct iscsi_uevent { struct msg_transport_disconnect { uint64_t ep_handle; } ep_disconnect; + struct msg_tgt_dscvr { + enum iscsi_tgt_dscvr type; + uint32_t host_no; + /* + * enable = 1 to establish a new connection + * with the server. enable = 0 to disconnect + * from the server. Used primarily to switch + * from one iSNS server to another. + */ + uint32_t enable; + } tgt_dscvr; } u; union { /* messages k -> u */ @@ -138,6 +158,10 @@ struct iscsi_uevent { uint32_t cid; uint32_t error; /* enum iscsi_err */ } connerror; + struct msg_session_destroyed { + uint32_t host_no; + uint32_t sid; + } d_session; struct msg_transport_connect_ret { uint64_t handle; } ep_connect_ret; diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index cbf7e58bd6f..ba2760802de 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -157,6 +157,11 @@ struct iscsi_conn { int max_xmit_dlength; /* target_max_recv_dsl */ int hdrdgst_en; int datadgst_en; + int ifmarker_en; + int ofmarker_en; + /* values userspace uses to id a conn */ + int persistent_port; + char *persistent_address; /* MIB-statistics */ uint64_t txdata_octets; @@ -196,8 +201,8 @@ struct iscsi_session { int pdu_inorder_en; int dataseq_inorder_en; int erl; - int ifmarker_en; - int ofmarker_en; + int tpgt; + char *targetname; /* control data */ struct iscsi_transport *tt; @@ -240,6 +245,10 @@ iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *, extern void iscsi_session_teardown(struct iscsi_cls_session *); extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); +extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen); +extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + enum iscsi_param param, char *buf); #define session_to_cls(_sess) \ hostdata_session(_sess->host->hostdata) @@ -255,6 +264,8 @@ extern void iscsi_conn_stop(struct iscsi_cls_conn *, int); extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, int); extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); +extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf); /* * pdu and task processing diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index e46cd404bd7..371f70d9aa9 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -143,7 +143,7 @@ struct scsi_cmnd { extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); -extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); +extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index a42efd6e4be..b3dd90f3e85 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -542,6 +542,9 @@ struct Scsi_Host { */ unsigned ordered_tag:1; + /* task mgmt function in progress */ + unsigned tmf_in_progress:1; + /* * Optional work queue to be utilized by the transport */ @@ -619,7 +622,8 @@ static inline int scsi_host_in_recovery(struct Scsi_Host *shost) { return shost->shost_state == SHOST_RECOVERY || shost->shost_state == SHOST_CANCEL_RECOVERY || - shost->shost_state == SHOST_DEL_RECOVERY; + shost->shost_state == SHOST_DEL_RECOVERY || + shost->tmf_in_progress; } extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b684426a590..5a3df1d7085 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -34,6 +34,7 @@ struct iscsi_cls_conn; struct iscsi_conn; struct iscsi_cmd_task; struct iscsi_mgmt_task; +struct sockaddr; /** * struct iscsi_transport - iSCSI Transport template @@ -46,7 +47,12 @@ struct iscsi_mgmt_task; * @bind_conn: associate this connection with existing iSCSI session * and specified transport descriptor * @destroy_conn: destroy inactive iSCSI connection - * @set_param: set iSCSI Data-Path operational parameter + * @set_param: set iSCSI parameter. Return 0 on success, -ENODATA + * when param is not supported, and a -Exx value on other + * error. + * @get_param get iSCSI parameter. Must return number of bytes + * copied to buffer on success, -ENODATA when param + * is not supported, and a -Exx value on other error * @start_conn: set connection to be operational * @stop_conn: suspend/recover/terminate connection * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. @@ -97,15 +103,11 @@ struct iscsi_transport { void (*stop_conn) (struct iscsi_cls_conn *conn, int flag); void (*destroy_conn) (struct iscsi_cls_conn *conn); int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param, - uint32_t value); + char *buf, int buflen); int (*get_conn_param) (struct iscsi_cls_conn *conn, - enum iscsi_param param, uint32_t *value); + enum iscsi_param param, char *buf); int (*get_session_param) (struct iscsi_cls_session *session, - enum iscsi_param param, uint32_t *value); - int (*get_conn_str_param) (struct iscsi_cls_conn *conn, - enum iscsi_param param, char *buf); - int (*get_session_str_param) (struct iscsi_cls_session *session, - enum iscsi_param param, char *buf); + enum iscsi_param param, char *buf); int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); void (*get_stats) (struct iscsi_cls_conn *conn, @@ -127,6 +129,8 @@ struct iscsi_transport { uint64_t *ep_handle); int (*ep_poll) (uint64_t ep_handle, int timeout_ms); void (*ep_disconnect) (uint64_t ep_handle); + int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no, + uint32_t enable, struct sockaddr *dst_addr); }; /* @@ -155,13 +159,6 @@ struct iscsi_cls_conn { struct iscsi_transport *transport; uint32_t cid; /* connection id */ - /* portal/group values we got during discovery */ - char *persistent_address; - int persistent_port; - /* portal/group values we are currently using */ - char *address; - int port; - int active; /* must be accessed with the connlock */ struct device dev; /* sysfs transport/container device */ struct mempool_zone *z_error; @@ -185,16 +182,11 @@ struct iscsi_cls_session { struct list_head host_list; struct iscsi_transport *transport; - /* iSCSI values used as unique id by userspace. */ - char *targetname; - int tpgt; - /* recovery fields */ int recovery_tmo; struct work_struct recovery_work; int target_id; - int channel; int sid; /* session id */ void *dd_data; /* LLD private data */ @@ -207,8 +199,10 @@ struct iscsi_cls_session { #define iscsi_session_to_shost(_session) \ dev_to_shost(_session->dev.parent) +#define starget_to_session(_stgt) \ + iscsi_dev_to_session(_stgt->dev.parent) + struct iscsi_host { - int next_target_id; struct list_head sessions; struct mutex mutex; }; @@ -216,8 +210,17 @@ struct iscsi_host { /* * session and connection functions that can be used by HW iSCSI LLDs */ +extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, + struct iscsi_transport *transport); +extern int iscsi_add_session(struct iscsi_cls_session *session, + unsigned int target_id); +extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn); +extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn); extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *t, int channel); + struct iscsi_transport *t, + unsigned int target_id); +extern void iscsi_remove_session(struct iscsi_cls_session *session); +extern void iscsi_free_session(struct iscsi_cls_session *session); extern int iscsi_destroy_session(struct iscsi_cls_session *session); extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, uint32_t cid); @@ -225,4 +228,5 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); + #endif diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 93cfb4bf421..e3c503cd175 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h @@ -3,6 +3,7 @@ #include <linux/transport_class.h> #include <linux/types.h> +#include <linux/mutex.h> struct scsi_transport_template; struct sas_rphy; @@ -55,7 +56,6 @@ struct sas_phy { enum sas_linkrate minimum_linkrate; enum sas_linkrate maximum_linkrate_hw; enum sas_linkrate maximum_linkrate; - u8 port_identifier; /* internal state */ unsigned int local_attached : 1; @@ -66,8 +66,8 @@ struct sas_phy { u32 loss_of_dword_sync_count; u32 phy_reset_problem_count; - /* the other end of the link */ - struct sas_rphy *rphy; + /* for the list of phys belonging to a port */ + struct list_head port_siblings; }; #define dev_to_phy(d) \ @@ -124,6 +124,24 @@ struct sas_expander_device { #define rphy_to_expander_device(r) \ container_of((r), struct sas_expander_device, rphy) +struct sas_port { + struct device dev; + + u8 port_identifier; + int num_phys; + + /* the other end of the link */ + struct sas_rphy *rphy; + + struct mutex phy_list_mutex; + struct list_head phy_list; +}; + +#define dev_to_sas_port(d) \ + container_of((d), struct sas_port, dev) +#define transport_class_to_sas_port(cdev) \ + dev_to_sas_port((cdev)->dev) + /* The functions by which the transport class and the driver communicate */ struct sas_function_template { int (*get_linkerrors)(struct sas_phy *); @@ -133,6 +151,7 @@ struct sas_function_template { }; +void sas_remove_children(struct device *); extern void sas_remove_host(struct Scsi_Host *); extern struct sas_phy *sas_phy_alloc(struct device *, int); @@ -141,13 +160,21 @@ extern int sas_phy_add(struct sas_phy *); extern void sas_phy_delete(struct sas_phy *); extern int scsi_is_sas_phy(const struct device *); -extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *); -extern struct sas_rphy *sas_expander_alloc(struct sas_phy *, enum sas_device_type); +extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); +extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); void sas_rphy_free(struct sas_rphy *); extern int sas_rphy_add(struct sas_rphy *); extern void sas_rphy_delete(struct sas_rphy *); extern int scsi_is_sas_rphy(const struct device *); +struct sas_port *sas_port_alloc(struct device *, int); +int sas_port_add(struct sas_port *); +void sas_port_free(struct sas_port *); +void sas_port_delete(struct sas_port *); +void sas_port_add_phy(struct sas_port *, struct sas_phy *); +void sas_port_delete_phy(struct sas_port *, struct sas_phy *); +int scsi_is_sas_port(const struct device *); + extern struct scsi_transport_template * sas_attach_transport(struct sas_function_template *); extern void sas_release_transport(struct scsi_transport_template *); |