[ewg] Re: [PATCH 2/2] IB/iser: add backport & kernel addons for open-iscsi over iSER support for RHAS4 up3 and up4
Michael S. Tsirkin
mst at dev.mellanox.co.il
Thu May 10 02:29:25 PDT 2007
> Quoting Erez Zilber <erezz at voltaire.com>:
> Subject: [PATCH 2/2] IB/iser: add backport & kernel addons for open-iscsi over iSER support for RHAS4 up3 and up4
>
>
> Add the required backport patches & kernel addons for open-iscsi
> over iSER in RHAS4 up3 and up4.
>
> Signed-off-by: Erez Zilber <erezz at voltaire.com>
In addition to posting patches, could you pls publish a git tree to pull from,
please? This makes it easy to test-build the patch as our build system
knows how to do git checkout.
---
Two comments, generally
A: Please move code from kernel_patches to kernel_addons as much
as possible. There are many places where you just add new headers,
or add #include directives, or change the function called or
remove extra parameters, all this can and should be done through addons.
B: Please do not add code to core unless there is more than 1 user -
add it to the iser module instead. This way if there is
compilation failure there, you do not break core for people.
Some specifics below:
....
> diff --git a/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch b/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch
> new file mode 100644
> index 0000000..c4df6bb
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch
> @@ -0,0 +1,591 @@
> +diff -rupN linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h linux-2.6.20/include/scsi/iscsi_proto.h
> +--- linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h 1970-01-01 02:00:00.000000000 +0200
> ++++ linux-2.6.20/include/scsi/iscsi_proto.h 2007-02-04 20:44:54.000000000 +0200
> +@@ -0,0 +1,587 @@
> ++/*
> ++ * RFC 3720 (iSCSI) protocol data types
> ++ *
> ++ * Copyright (C) 2005 Dmitry Yusupov
> ++ * Copyright (C) 2005 Alex Aizman
> ++ * maintained by open-iscsi at googlegroups.com
> ++ *
> ++ * This program is free software; you can redistribute it and/or modify
> ++ * it under the terms of the GNU General Public License as published
> ++ * by the Free Software Foundation; either version 2 of the License, or
> ++ * (at your option) any later version.
> ++ *
> ++ * This program is distributed in the hope that it will be useful, but
> ++ * WITHOUT ANY WARRANTY; without even the implied warranty of
> ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> ++ * General Public License for more details.
> ++ *
> ++ * See the file COPYING included with this distribution for more details.
> ++ */
> ++
> ++#ifndef ISCSI_PROTO_H
> ++#define ISCSI_PROTO_H
> ++
> ++#define ISCSI_DRAFT20_VERSION 0x00
> ++
> ++/* default iSCSI listen port for incoming connections */
> ++#define ISCSI_LISTEN_PORT 3260
> ++
> ++/* Padding word length */
> ++#define PAD_WORD_LEN 4
> ++
> ++/*
> ++ * useful common(control and data pathes) macro
> ++ */
> ++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
> ++#define hton24(p, v) { \
> ++ p[0] = (((v) >> 16) & 0xFF); \
> ++ p[1] = (((v) >> 8) & 0xFF); \
> ++ p[2] = ((v) & 0xFF); \
> ++}
> ++#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
> ++
> ++/*
> ++ * iSCSI Template Message Header
> ++ */
> ++struct iscsi_hdr {
> ++ uint8_t opcode;
> ++ uint8_t flags; /* Final bit */
> ++ uint8_t rsvd2[2];
> ++ uint8_t hlength; /* AHSs total length */
> ++ uint8_t dlength[3]; /* Data length */
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 ttt; /* Target Task Tag */
> ++ __be32 statsn;
> ++ __be32 exp_statsn;
> ++ __be32 max_statsn;
> ++ uint8_t other[12];
> ++};
> ++
> ++/************************* RFC 3720 Begin *****************************/
> ++
> ++#define ISCSI_RESERVED_TAG 0xffffffff
> ++
> ++/* Opcode encoding bits */
> ++#define ISCSI_OP_RETRY 0x80
> ++#define ISCSI_OP_IMMEDIATE 0x40
> ++#define ISCSI_OPCODE_MASK 0x3F
> ++
> ++/* Initiator Opcode values */
> ++#define ISCSI_OP_NOOP_OUT 0x00
> ++#define ISCSI_OP_SCSI_CMD 0x01
> ++#define ISCSI_OP_SCSI_TMFUNC 0x02
> ++#define ISCSI_OP_LOGIN 0x03
> ++#define ISCSI_OP_TEXT 0x04
> ++#define ISCSI_OP_SCSI_DATA_OUT 0x05
> ++#define ISCSI_OP_LOGOUT 0x06
> ++#define ISCSI_OP_SNACK 0x10
> ++
> ++#define ISCSI_OP_VENDOR1_CMD 0x1c
> ++#define ISCSI_OP_VENDOR2_CMD 0x1d
> ++#define ISCSI_OP_VENDOR3_CMD 0x1e
> ++#define ISCSI_OP_VENDOR4_CMD 0x1f
> ++
> ++/* Target Opcode values */
> ++#define ISCSI_OP_NOOP_IN 0x20
> ++#define ISCSI_OP_SCSI_CMD_RSP 0x21
> ++#define ISCSI_OP_SCSI_TMFUNC_RSP 0x22
> ++#define ISCSI_OP_LOGIN_RSP 0x23
> ++#define ISCSI_OP_TEXT_RSP 0x24
> ++#define ISCSI_OP_SCSI_DATA_IN 0x25
> ++#define ISCSI_OP_LOGOUT_RSP 0x26
> ++#define ISCSI_OP_R2T 0x31
> ++#define ISCSI_OP_ASYNC_EVENT 0x32
> ++#define ISCSI_OP_REJECT 0x3f
> ++
> ++struct iscsi_ahs_hdr {
> ++ __be16 ahslength;
> ++ uint8_t ahstype;
> ++ uint8_t ahspec[5];
> ++};
> ++
> ++#define ISCSI_AHSTYPE_CDB 1
> ++#define ISCSI_AHSTYPE_RLENGTH 2
> ++
> ++/* iSCSI PDU Header */
> ++struct iscsi_cmd {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ __be16 rsvd2;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 data_length;
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ uint8_t cdb[16]; /* SCSI Command Block */
> ++ /* Additional Data (Command Dependent) */
> ++};
> ++
> ++/* Command PDU flags */
> ++#define ISCSI_FLAG_CMD_FINAL 0x80
> ++#define ISCSI_FLAG_CMD_READ 0x40
> ++#define ISCSI_FLAG_CMD_WRITE 0x20
> ++#define ISCSI_FLAG_CMD_ATTR_MASK 0x07 /* 3 bits */
> ++
> ++/* SCSI Command Attribute values */
> ++#define ISCSI_ATTR_UNTAGGED 0
> ++#define ISCSI_ATTR_SIMPLE 1
> ++#define ISCSI_ATTR_ORDERED 2
> ++#define ISCSI_ATTR_HEAD_OF_QUEUE 3
> ++#define ISCSI_ATTR_ACA 4
> ++
> ++struct iscsi_rlength_ahdr {
> ++ __be16 ahslength;
> ++ uint8_t ahstype;
> ++ uint8_t reserved;
> ++ __be32 read_length;
> ++};
> ++
> ++/* SCSI Response Header */
> ++struct iscsi_cmd_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t response;
> ++ uint8_t cmd_status;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 rsvd1;
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ __be32 exp_datasn;
> ++ __be32 bi_residual_count;
> ++ __be32 residual_count;
> ++ /* Response or Sense Data (optional) */
> ++};
> ++
> ++/* Command Response PDU flags */
> ++#define ISCSI_FLAG_CMD_BIDI_OVERFLOW 0x10
> ++#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW 0x08
> ++#define ISCSI_FLAG_CMD_OVERFLOW 0x04
> ++#define ISCSI_FLAG_CMD_UNDERFLOW 0x02
> ++
> ++/* iSCSI Status values. Valid if Rsp Selector bit is not set */
> ++#define ISCSI_STATUS_CMD_COMPLETED 0
> ++#define ISCSI_STATUS_TARGET_FAILURE 1
> ++#define ISCSI_STATUS_SUBSYS_FAILURE 2
> ++
> ++/* Asynchronous Event Header */
> ++struct iscsi_async {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[2];
> ++ uint8_t rsvd3;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ uint8_t rsvd4[8];
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ uint8_t async_event;
> ++ uint8_t async_vcode;
> ++ __be16 param1;
> ++ __be16 param2;
> ++ __be16 param3;
> ++ uint8_t rsvd5[4];
> ++};
> ++
> ++/* iSCSI Event Codes */
> ++#define ISCSI_ASYNC_MSG_SCSI_EVENT 0
> ++#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT 1
> ++#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION 2
> ++#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS 3
> ++#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION 4
> ++#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC 255
> ++
> ++/* NOP-Out Message */
> ++struct iscsi_nopout {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ __be16 rsvd2;
> ++ uint8_t rsvd3;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 ttt; /* Target Transfer Tag */
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ uint8_t rsvd4[16];
> ++};
> ++
> ++/* NOP-In Message */
> ++struct iscsi_nopin {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ __be16 rsvd2;
> ++ uint8_t rsvd3;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 ttt; /* Target Transfer Tag */
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ uint8_t rsvd4[12];
> ++};
> ++
> ++/* SCSI Task Management Message Header */
> ++struct iscsi_tm {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd1[2];
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 rtt; /* Reference Task Tag */
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ __be32 refcmdsn;
> ++ __be32 exp_datasn;
> ++ uint8_t rsvd2[8];
> ++};
> ++
> ++#define ISCSI_FLAG_TM_FUNC_MASK 0x7F
> ++
> ++/* Function values */
> ++#define ISCSI_TM_FUNC_ABORT_TASK 1
> ++#define ISCSI_TM_FUNC_ABORT_TASK_SET 2
> ++#define ISCSI_TM_FUNC_CLEAR_ACA 3
> ++#define ISCSI_TM_FUNC_CLEAR_TASK_SET 4
> ++#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET 5
> ++#define ISCSI_TM_FUNC_TARGET_WARM_RESET 6
> ++#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
> ++#define ISCSI_TM_FUNC_TASK_REASSIGN 8
> ++
> ++/* SCSI Task Management Response Header */
> ++struct iscsi_tm_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t response; /* see Response values below */
> ++ uint8_t qualifier;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd2[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 rtt; /* Reference Task Tag */
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ uint8_t rsvd3[12];
> ++};
> ++
> ++/* Response values */
> ++#define ISCSI_TMF_RSP_COMPLETE 0x00
> ++#define ISCSI_TMF_RSP_NO_TASK 0x01
> ++#define ISCSI_TMF_RSP_NO_LUN 0x02
> ++#define ISCSI_TMF_RSP_TASK_ALLEGIANT 0x03
> ++#define ISCSI_TMF_RSP_NO_FAILOVER 0x04
> ++#define ISCSI_TMF_RSP_NOT_SUPPORTED 0x05
> ++#define ISCSI_TMF_RSP_AUTH_FAILED 0x06
> ++#define ISCSI_TMF_RSP_REJECTED 0xff
> ++
> ++/* Ready To Transfer Header */
> ++struct iscsi_r2t_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[2];
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 ttt; /* Target Transfer Tag */
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ __be32 r2tsn;
> ++ __be32 data_offset;
> ++ __be32 data_length;
> ++};
> ++
> ++/* SCSI Data Hdr */
> ++struct iscsi_data {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[2];
> ++ uint8_t rsvd3;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt;
> ++ __be32 ttt;
> ++ __be32 rsvd4;
> ++ __be32 exp_statsn;
> ++ __be32 rsvd5;
> ++ __be32 datasn;
> ++ __be32 offset;
> ++ __be32 rsvd6;
> ++ /* Payload */
> ++};
> ++
> ++/* SCSI Data Response Hdr */
> ++struct iscsi_data_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2;
> ++ uint8_t cmd_status;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t lun[8];
> ++ __be32 itt;
> ++ __be32 ttt;
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ __be32 datasn;
> ++ __be32 offset;
> ++ __be32 residual_count;
> ++};
> ++
> ++/* Data Response PDU flags */
> ++#define ISCSI_FLAG_DATA_ACK 0x40
> ++#define ISCSI_FLAG_DATA_OVERFLOW 0x04
> ++#define ISCSI_FLAG_DATA_UNDERFLOW 0x02
> ++#define ISCSI_FLAG_DATA_STATUS 0x01
> ++
> ++/* Text Header */
> ++struct iscsi_text {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[2];
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd4[8];
> ++ __be32 itt;
> ++ __be32 ttt;
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ uint8_t rsvd5[16];
> ++ /* Text - key=value pairs */
> ++};
> ++
> ++#define ISCSI_FLAG_TEXT_CONTINUE 0x40
> ++
> ++/* Text Response Header */
> ++struct iscsi_text_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[2];
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd4[8];
> ++ __be32 itt;
> ++ __be32 ttt;
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ uint8_t rsvd5[12];
> ++ /* Text Response - key:value pairs */
> ++};
> ++
> ++/* Login Header */
> ++struct iscsi_login {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t max_version; /* Max. version supported */
> ++ uint8_t min_version; /* Min. version supported */
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t isid[6]; /* Initiator Session ID */
> ++ __be16 tsih; /* Target Session Handle */
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be16 cid;
> ++ __be16 rsvd3;
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ uint8_t rsvd5[16];
> ++};
> ++
> ++/* Login PDU flags */
> ++#define ISCSI_FLAG_LOGIN_TRANSIT 0x80
> ++#define ISCSI_FLAG_LOGIN_CONTINUE 0x40
> ++#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK 0x0C /* 2 bits */
> ++#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */
> ++
> ++#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
> ++ ((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
> ++#define ISCSI_LOGIN_NEXT_STAGE(flags) \
> ++ (flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
> ++
> ++/* Login Response Header */
> ++struct iscsi_login_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t max_version; /* Max. version supported */
> ++ uint8_t active_version; /* Active version */
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t isid[6]; /* Initiator Session ID */
> ++ __be16 tsih; /* Target Session Handle */
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 rsvd3;
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ uint8_t status_class; /* see Login RSP ststus classes below */
> ++ uint8_t status_detail; /* see Login RSP Status details below */
> ++ uint8_t rsvd4[10];
> ++};
> ++
> ++/* Login stage (phase) codes for CSG, NSG */
> ++#define ISCSI_INITIAL_LOGIN_STAGE -1
> ++#define ISCSI_SECURITY_NEGOTIATION_STAGE 0
> ++#define ISCSI_OP_PARMS_NEGOTIATION_STAGE 1
> ++#define ISCSI_FULL_FEATURE_PHASE 3
> ++
> ++/* Login Status response classes */
> ++#define ISCSI_STATUS_CLS_SUCCESS 0x00
> ++#define ISCSI_STATUS_CLS_REDIRECT 0x01
> ++#define ISCSI_STATUS_CLS_INITIATOR_ERR 0x02
> ++#define ISCSI_STATUS_CLS_TARGET_ERR 0x03
> ++
> ++/* Login Status response detail codes */
> ++/* Class-0 (Success) */
> ++#define ISCSI_LOGIN_STATUS_ACCEPT 0x00
> ++
> ++/* Class-1 (Redirection) */
> ++#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP 0x01
> ++#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM 0x02
> ++
> ++/* Class-2 (Initiator Error) */
> ++#define ISCSI_LOGIN_STATUS_INIT_ERR 0x00
> ++#define ISCSI_LOGIN_STATUS_AUTH_FAILED 0x01
> ++#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN 0x02
> ++#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND 0x03
> ++#define ISCSI_LOGIN_STATUS_TGT_REMOVED 0x04
> ++#define ISCSI_LOGIN_STATUS_NO_VERSION 0x05
> ++#define ISCSI_LOGIN_STATUS_ISID_ERROR 0x06
> ++#define ISCSI_LOGIN_STATUS_MISSING_FIELDS 0x07
> ++#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED 0x08
> ++#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE 0x09
> ++#define ISCSI_LOGIN_STATUS_NO_SESSION 0x0a
> ++#define ISCSI_LOGIN_STATUS_INVALID_REQUEST 0x0b
> ++
> ++/* Class-3 (Target Error) */
> ++#define ISCSI_LOGIN_STATUS_TARGET_ERROR 0x00
> ++#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE 0x01
> ++#define ISCSI_LOGIN_STATUS_NO_RESOURCES 0x02
> ++
> ++/* Logout Header */
> ++struct iscsi_logout {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd1[2];
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd2[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be16 cid;
> ++ uint8_t rsvd3[2];
> ++ __be32 cmdsn;
> ++ __be32 exp_statsn;
> ++ uint8_t rsvd4[16];
> ++};
> ++
> ++/* Logout PDU flags */
> ++#define ISCSI_FLAG_LOGOUT_REASON_MASK 0x7F
> ++
> ++/* logout reason_code values */
> ++
> ++#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0
> ++#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1
> ++#define ISCSI_LOGOUT_REASON_RECOVERY 2
> ++#define ISCSI_LOGOUT_REASON_AEN_REQUEST 3
> ++
> ++/* Logout Response Header */
> ++struct iscsi_logout_rsp {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t response; /* see Logout response values below */
> ++ uint8_t rsvd2;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd3[8];
> ++ __be32 itt; /* Initiator Task Tag */
> ++ __be32 rsvd4;
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ __be32 rsvd5;
> ++ __be16 t2wait;
> ++ __be16 t2retain;
> ++ __be32 rsvd6;
> ++};
> ++
> ++/* logout response status values */
> ++
> ++#define ISCSI_LOGOUT_SUCCESS 0
> ++#define ISCSI_LOGOUT_CID_NOT_FOUND 1
> ++#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED 2
> ++#define ISCSI_LOGOUT_CLEANUP_FAILED 3
> ++
> ++/* SNACK Header */
> ++struct iscsi_snack {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t rsvd2[14];
> ++ __be32 itt;
> ++ __be32 begrun;
> ++ __be32 runlength;
> ++ __be32 exp_statsn;
> ++ __be32 rsvd3;
> ++ __be32 exp_datasn;
> ++ uint8_t rsvd6[8];
> ++};
> ++
> ++/* SNACK PDU flags */
> ++#define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */
> ++
> ++/* Reject Message Header */
> ++struct iscsi_reject {
> ++ uint8_t opcode;
> ++ uint8_t flags;
> ++ uint8_t reason;
> ++ uint8_t rsvd2;
> ++ uint8_t hlength;
> ++ uint8_t dlength[3];
> ++ uint8_t rsvd3[8];
> ++ __be32 ffffffff;
> ++ uint8_t rsvd4[4];
> ++ __be32 statsn;
> ++ __be32 exp_cmdsn;
> ++ __be32 max_cmdsn;
> ++ __be32 datasn;
> ++ uint8_t rsvd5[8];
> ++ /* Text - Rejected hdr */
> ++};
> ++
> ++/* Reason for Reject */
> ++#define ISCSI_REASON_CMD_BEFORE_LOGIN 1
> ++#define ISCSI_REASON_DATA_DIGEST_ERROR 2
> ++#define ISCSI_REASON_DATA_SNACK_REJECT 3
> ++#define ISCSI_REASON_PROTOCOL_ERROR 4
> ++#define ISCSI_REASON_CMD_NOT_SUPPORTED 5
> ++#define ISCSI_REASON_IMM_CMD_REJECT 6
> ++#define ISCSI_REASON_TASK_IN_PROGRESS 7
> ++#define ISCSI_REASON_INVALID_SNACK 8
> ++#define ISCSI_REASON_BOOKMARK_INVALID 9
> ++#define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10
> ++#define ISCSI_REASON_NEGOTIATION_RESET 11
> ++
> ++/* Max. number of Key=Value pairs in a text message */
> ++#define MAX_KEY_VALUE_PAIRS 8192
> ++
> ++/* maximum length for text keys/values */
> ++#define KEY_MAXLEN 64
> ++#define VALUE_MAXLEN 255
> ++#define TARGET_NAME_MAXLEN VALUE_MAXLEN
> ++
> ++#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192
> ++
> ++/************************* RFC 3720 End *****************************/
> ++
> ++#endif /* ISCSI_PROTO_H */
Why isn't the above in addons?
...
> diff --git a/kernel_patches/backport/2.6.9_U3/add_memory_h.patch b/kernel_patches/backport/2.6.9_U3/add_memory_h.patch
> new file mode 100644
> index 0000000..5daad2e
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/add_memory_h.patch
> @@ -0,0 +1,93 @@
> +diff -rupN linux-2.6.20-like-rh4/include/linux/memory.h linux-2.6.20/include/linux/memory.h
> +--- linux-2.6.20-like-rh4/include/linux/memory.h 1970-01-01 02:00:00.000000000 +0200
> ++++ linux-2.6.20/include/linux/memory.h 2007-02-04 20:44:54.000000000 +0200
> +@@ -0,0 +1,89 @@
> ++/*
> ++ * include/linux/memory.h - generic memory definition
> ++ *
> ++ * This is mainly for topological representation. We define the
> ++ * basic "struct memory_block" here, which can be embedded in per-arch
> ++ * definitions or NUMA information.
> ++ *
> ++ * Basic handling of the devices is done in drivers/base/memory.c
> ++ * and system devices are handled in drivers/base/sys.c.
> ++ *
> ++ * Memory block are exported via sysfs in the class/memory/devices/
> ++ * directory.
> ++ *
> ++ */
> ++#ifndef _LINUX_MEMORY_H_
> ++#define _LINUX_MEMORY_H_
> ++
> ++#include <linux/sysdev.h>
> ++#include <linux/node.h>
> ++#include <linux/compiler.h>
> ++
> ++#include <asm/semaphore.h>
> ++
> ++struct memory_block {
> ++ unsigned long phys_index;
> ++ unsigned long state;
> ++ /*
> ++ * This serializes all state change requests. It isn't
> ++ * held during creation because the control files are
> ++ * created long after the critical areas during
> ++ * initialization.
> ++ */
> ++ struct semaphore state_sem;
> ++ int phys_device; /* to which fru does this belong? */
> ++ void *hw; /* optional pointer to fw/hw data */
> ++ int (*phys_callback)(struct memory_block *);
> ++ struct sys_device sysdev;
> ++};
> ++
> ++/* These states are exposed to userspace as text strings in sysfs */
> ++#define MEM_ONLINE (1<<0) /* exposed to userspace */
> ++#define MEM_GOING_OFFLINE (1<<1) /* exposed to userspace */
> ++#define MEM_OFFLINE (1<<2) /* exposed to userspace */
> ++
> ++/*
> ++ * All of these states are currently kernel-internal for notifying
> ++ * kernel components and architectures.
> ++ *
> ++ * For MEM_MAPPING_INVALID, all notifier chains with priority >0
> ++ * are called before pfn_to_page() becomes invalid. The priority=0
> ++ * entry is reserved for the function that actually makes
> ++ * pfn_to_page() stop working. Any notifiers that want to be called
> ++ * after that should have priority <0.
> ++ */
> ++#define MEM_MAPPING_INVALID (1<<3)
> ++
> ++struct notifier_block;
> ++struct mem_section;
> ++
> ++#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
> ++static inline int memory_dev_init(void)
> ++{
> ++ return 0;
> ++}
> ++static inline int register_memory_notifier(struct notifier_block *nb)
> ++{
> ++ return 0;
> ++}
> ++static inline void unregister_memory_notifier(struct notifier_block *nb)
> ++{
> ++}
> ++#else
> ++extern int register_new_memory(struct mem_section *);
> ++extern int unregister_memory_section(struct mem_section *);
> ++extern int memory_dev_init(void);
> ++extern int remove_memory_block(unsigned long, struct mem_section *, int);
> ++
> ++#define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT)
> ++
> ++
> ++#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
> ++
> ++#define hotplug_memory_notifier(fn, pri) { \
> ++ static struct notifier_block fn##_mem_nb = \
> ++ { .notifier_call = fn, .priority = pri }; \
> ++ register_memory_notifier(&fn##_mem_nb); \
> ++}
> ++
> ++#endif /* _LINUX_MEMORY_H_ */
why isn't this in addons?
> diff --git a/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch b/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch
> new file mode 100644
> index 0000000..d77c663
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch
> @@ -0,0 +1,504 @@
> +diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.c linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c
> +--- linux-2.6.20/drivers/scsi/iscsi_tcp.c 2007-02-04 20:44:54.000000000 +0200
> ++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c 2007-04-01 13:11:17.000000000 +0300
...
> +@@ -108,7 +108,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn
> + {
> + struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
> +
> +- crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
> ++ crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
> + buf->sg.length = tcp_conn->hdr_size;
> + }
> +
You could make it a macro in addons if you had named the new field tx_hash.
> +@@ -419,7 +419,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
> + tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
> + list_move_tail(&ctask->running, &conn->xmitqueue);
> +
> +- scsi_queue_work(session->host, &conn->xmitwork);
> ++ schedule_work(&conn->xmitwork);
> + conn->r2t_pdus_cnt++;
> + spin_unlock(&session->lock);
> +
Can not this be done with a macro in addons?
Same for other places where this change was done.
> +@@ -2044,11 +2037,13 @@ iscsi_tcp_conn_get_param(struct iscsi_cl
> + sk = tcp_conn->sock->sk;
> + if (sk->sk_family == PF_INET) {
> + inet = inet_sk(sk);
> +- len = sprintf(buf, NIPQUAD_FMT "\n",
> ++ len = sprintf(buf, "%u.%u.%u.%u\n",
> + NIPQUAD(inet->daddr));
> + } else {
> + np = inet6_sk(sk);
> +- len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
> ++ len = sprintf(buf,
> ++ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
> ++ NIP6(np->daddr));
> + }
> + mutex_unlock(&conn->xmitmutex);
> + break;
NIP6_FMT should be defined in addons.
> +@@ -2135,7 +2130,6 @@ static void iscsi_tcp_session_destroy(st
> + static struct scsi_host_template iscsi_sht = {
> + .name = "iSCSI Initiator over TCP/IP",
> + .queuecommand = iscsi_queuecommand,
> +- .change_queue_depth = iscsi_change_queue_depth,
> + .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
> + .sg_tablesize = ISCSI_SG_TABLESIZE,
> + .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
> +diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.h linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h
> +--- linux-2.6.20/drivers/scsi/iscsi_tcp.h 2007-02-04 20:44:54.000000000 +0200
> ++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h 2007-04-01 13:11:55.000000000 +0300
> +@@ -49,7 +49,6 @@
> + #define ISCSI_SG_TABLESIZE SG_ALL
> + #define ISCSI_TCP_MAX_CMD_LEN 16
> +
> +-struct crypto_hash;
> + struct socket;
> +
> + /* Socket connection recieve helper */
> +@@ -93,8 +92,8 @@ struct iscsi_tcp_conn {
> + void (*old_write_space)(struct sock *);
> +
> + /* data and header digests */
> +- struct hash_desc tx_hash; /* CRC32C (Tx) */
> +- struct hash_desc rx_hash; /* CRC32C (Rx) */
> ++ struct crypto_tfm *tx_tfm; /* CRC32C (Tx) */
> ++ struct crypto_tfm *rx_tfm; /* CRC32C (Rx) */
> +
> + /* MIB custom statistics */
> + uint32_t sendpage_failures_cnt;
Name the new field tx_hash (just change the type) and then
you will be able to replace a lot of changes by a one liner in addons.
> +diff -rup linux-2.6.20/drivers/scsi/libiscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c
> +--- linux-2.6.20/drivers/scsi/libiscsi.c 2007-02-04 20:44:54.000000000 +0200
> ++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c 2007-04-01 13:15:57.000000000 +0300
> +@@ -23,6 +23,7 @@
> + */
> + #include <linux/types.h>
> + #include <linux/mutex.h>
> ++#include <linux/gfp.h>
> + #include <linux/kfifo.h>
> + #include <linux/delay.h>
> + #include <net/tcp.h>
Why does this need to be added?
Such stuff should be done through addons.
....
> +diff -rup linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c
> +--- linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c 2007-02-04 20:44:54.000000000 +0200
> ++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c 2007-04-01 13:18:33.000000000 +0300
> +@@ -29,11 +29,15 @@
> + #include <scsi/scsi_transport.h>
> + #include <scsi/scsi_transport_iscsi.h>
> + #include <scsi/iscsi_if.h>
> ++#include <linux/transport_class.h>
> ++#include <linux/netlink.h>
Do this through addons.
> +
> + #define ISCSI_SESSION_ATTRS 11
> + #define ISCSI_CONN_ATTRS 11
> + #define ISCSI_HOST_ATTRS 0
> +-#define ISCSI_TRANSPORT_VERSION "2.0-724"
> ++#define ISCSI_TRANSPORT_VERSION "2.0-754"
Really a necessary change?
> ++
> ++#define SCAN_WILD_CARD ~0
Do this through addons.
> +
> + struct iscsi_internal {
> + int daemon_pid;
> +@@ -65,6 +69,8 @@ static DEFINE_SPINLOCK(iscsi_transport_l
> + #define cdev_to_iscsi_internal(_cdev) \
> + container_of(_cdev, struct iscsi_internal, cdev)
> +
> ++extern int attribute_container_init(void);
> ++
This does not look scsi-related. Why does this belong here?
> +@@ -216,28 +225,10 @@ static int iscsi_is_session_dev(const st
> + return dev->release == iscsi_session_release;
> + }
> +
> +-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
> +- uint id, uint lun)
> +-{
> +- struct iscsi_host *ihost = shost->shost_data;
> +- struct iscsi_cls_session *session;
> +-
> +- mutex_lock(&ihost->mutex);
> +- list_for_each_entry(session, &ihost->sessions, host_list) {
> +- if ((channel == SCAN_WILD_CARD || channel == 0) &&
> +- (id == SCAN_WILD_CARD || id == session->target_id))
> +- scsi_scan_target(&session->dev, 0,
> +- session->target_id, lun, 1);
> +- }
> +- mutex_unlock(&ihost->mutex);
> +-
> +- return 0;
> +-}
> +-
> +-static void session_recovery_timedout(struct work_struct *work)
> ++static void session_recovery_timedout(void *data)
> + {
> + struct iscsi_cls_session *session =
> +- container_of(work, struct iscsi_cls_session,
> ++ container_of(data, struct iscsi_cls_session,
> + recovery_work.work);
> +
> + dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
you should not need this.
This looks like it duplcates the work we did on
backporting work_struct to old kernels.
> +@@ -452,6 +441,7 @@ iscsi_create_conn(struct iscsi_cls_sessi
> + goto release_parent_ref;
> + }
> + transport_register_device(&conn->dev);
> ++
> + return conn;
> +
> + release_parent_ref:
Really necessary in a backport?
> +@@ -606,9 +596,8 @@ iscsi_if_send_reply(int pid, int seq, in
> + struct nlmsghdr *nlh;
> + int len = NLMSG_SPACE(size);
> + int flags = multi ? NLM_F_MULTI : 0;
> +- int t = done ? NLMSG_DONE : type;
> +
> +- skb = alloc_skb(len, GFP_ATOMIC);
> ++ skb = alloc_skb(len, GFP_KERNEL);
> + /*
> + * FIXME:
> + * user is supposed to react on iferror == -ENOMEM;
This looks really strange in a backport.
> +@@ -649,7 +638,7 @@ iscsi_if_get_stats(struct iscsi_transpor
> + do {
> + int actual_size;
> +
> +- skbstat = alloc_skb(len, GFP_ATOMIC);
> ++ skbstat = alloc_skb(len, GFP_KERNEL);
> + if (!skbstat) {
> + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
> + "deliver stats: OOM\n");
As does this.
....
> diff --git a/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch b/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch
> new file mode 100644
> index 0000000..6dd4429
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch
> @@ -0,0 +1,60 @@
> +diff -rupN linux-2.6.20-rc7/include/scsi/iscsi_compat.h linux-2.6.9/include/scsi/iscsi_compat.h
> +--- linux-2.6.20-rc7/include/scsi/iscsi_compat.h 1970-01-01 02:00:00.000000000 +0200
> ++++ linux-2.6.9/include/scsi/iscsi_compat.h 2007-02-08 08:45:39.000000000 +0200
Why isn't this in addons?
> diff --git a/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch b/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch
> new file mode 100644
> index 0000000..f2425e0
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch
> @@ -0,0 +1,104 @@
> +diff -rupN linux-2.6.20-like-rh4/include/linux/transport_class.h linux-2.6.20/include/linux/transport_class.h
> +--- linux-2.6.20-like-rh4/include/linux/transport_class.h 1970-01-01 02:00:00.000000000 +0200
> ++++ linux-2.6.20/include/linux/transport_class.h 2007-02-04 20:44:54.000000000 +0200
Why isn't this in addons?
> diff --git a/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch b/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch
> new file mode 100644
> index 0000000..3c2a969
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch
> @@ -0,0 +1,13 @@
> +--- linux-2.6.20-rc7-orig/drivers/infiniband/ulp/iser/iscsi_iser.c 2007-02-08 09:13:43.000000000 +0200
> ++++ linux-2.6.20-rc7/drivers/infiniband/ulp/iser/iscsi_iser.c 2007-02-08 09:14:31.000000000 +0200
> +@@ -70,9 +70,8 @@
> + #include <scsi/scsi_tcq.h>
> + #include <scsi/scsi_host.h>
> + #include <scsi/scsi.h>
> +-#include <scsi/scsi_transport_iscsi.h>
> +-
> + #include "iscsi_iser.h"
> ++#include <scsi/scsi_transport_iscsi.h>
> +
> + static unsigned int iscsi_max_lun = 512;
> + module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
Looks like the right thing to do anyway.
So put it in fixes instead, and post upstream.
> diff --git a/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch b/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
> index e84b964..52c0136 100644
> --- a/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
> +++ b/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
> @@ -19,6 +19,62 @@ index 0000000..58cf933
> +++ b/drivers/infiniband/core/kfifo.c
> @@ -0,0 +1 @@
> +#include "src/kfifo.c"
> +diff --git a/drivers/infiniband/core/init.c b/drivers/infiniband/core/init.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/init.c
> +@@ -0,0 +1 @@
> ++#include "src/init.c"
> +diff --git a/drivers/infiniband/core/attribute_container.c b/drivers/infiniband/core/attribute_container.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/attribute_container.c
> +@@ -0,0 +1 @@
> ++#include "src/attribute_container.c"
> +diff --git a/drivers/infiniband/core/transport_class.c b/drivers/infiniband/core/transport_class.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/transport_class.c
> +@@ -0,0 +1 @@
> ++#include "src/transport_class.c"
> +diff --git a/drivers/infiniband/core/klist.c b/drivers/infiniband/core/klist.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/klist.c
> +@@ -0,0 +1 @@
> ++#include "src/klist.c"
> +diff --git a/drivers/infiniband/core/scsi.c b/drivers/infiniband/core/scsi.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/scsi.c
> +@@ -0,0 +1 @@
> ++#include "src/scsi.c"
> +diff --git a/drivers/infiniband/core/scsi_lib.c b/drivers/infiniband/core/scsi_lib.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/scsi_lib.c
> +@@ -0,0 +1 @@
> ++#include "src/scsi_lib.c"
> +diff --git a/drivers/infiniband/core/scsi_scan.c b/drivers/infiniband/core/scsi_scan.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/scsi_scan.c
> +@@ -0,0 +1 @@
> ++#include "src/scsi_scan.c"
> +diff --git a/drivers/infiniband/core/kref_new.c b/drivers/infiniband/core/kref_new.c
> +new file mode 100644
> +index 0000000..58cf933
> +--- /dev/null
> ++++ b/drivers/infiniband/core/kref_new.c
> +@@ -0,0 +1 @@
> ++#include "src/kref_new.c"
> diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
> index 50fb1cd..456bfd0 100644
> --- a/drivers/infiniband/core/Makefile
> @@ -28,4 +84,4 @@ index 50fb1cd..456bfd0 100644
> ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o \
> uverbs_marshall.o
> +
> -+ib_core-y += genalloc.o netevent.o kfifo.o
> ++ib_core-y += genalloc.o netevent.o kfifo.o scsi.o scsi_lib.o scsi_scan.o init.o attribute_container.o transport_class.o klist.o kref_new.o
Can we make these part of iser place?
Linking scsi stuff into core does not look right.
> diff --git a/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch b/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch
> new file mode 100644
> index 0000000..cc071ef
> --- /dev/null
> +++ b/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch
> @@ -0,0 +1,247 @@
> +diff -rupN linux-2.6.20-like-rh4/include/linux/netlink.h linux-2.6.20/include/linux/netlink.h
> +--- linux-2.6.20-like-rh4/include/linux/netlink.h 1970-01-01 02:00:00.000000000 +0200
> ++++ linux-2.6.20/include/linux/netlink.h 2007-02-04 20:44:54.000000000 +0200
Belongs in addons.
--
MST
More information about the ewg
mailing list