From 2316ebc0566e6518787c27b459ba6a311b1d9c5c Mon Sep 17 00:00:00 2001 From: Payes Date: Wed, 28 Feb 2018 20:21:01 +0530 Subject: [PATCH] iSCSI target implementaion --- ChangeLog.jp | 850 +++ INSTALL | 28 + LICENSE | 23 + Makefile | 95 + Makefile.in | 95 + README.md | 0 config.guess | 1407 +++++ config.log | 2965 ++++++++++ config.status | 1075 ++++ config.sub | 1504 +++++ configure | 6464 ++++++++++++++++++++++ configure.in | 389 ++ doc/Makefile | 78 + doc/Makefile.in | 78 + doc/QUICKSTART | 51 + doc/QUICKSTART.jp | 61 + doc/istgt.1.in | 59 + etc/Makefile | 96 + etc/Makefile.in | 96 + etc/auth.conf | 24 + etc/istgt.conf.in | 180 + etc/istgt.large.conf.in | 310 ++ etc/istgt.sh.in | 24 + etc/istgt_linux.sh.in | 62 + etc/istgt_netbsd.sh.in | 18 + etc/istgtcontrol.conf | 31 + install-sh | 527 ++ src/Makefile | 139 + src/Makefile.in | 139 + src/build.h | 35 + src/build.h.in | 35 + src/config.h | 323 ++ src/config.h.in | 322 ++ src/istgt.c | 2977 ++++++++++ src/istgt.conf | 62 + src/istgt.h | 385 ++ src/istgt_cmd_table.c | 1108 ++++ src/istgt_conf.c | 557 ++ src/istgt_conf.h | 79 + src/istgt_crc32c.c | 209 + src/istgt_crc32c.h | 49 + src/istgt_iscsi.c | 7380 +++++++++++++++++++++++++ src/istgt_iscsi.h | 373 ++ src/istgt_iscsi_param.c | 244 + src/istgt_iscsi_param.h | 60 + src/istgt_iscsi_xcopy.h | 70 + src/istgt_log.c | 254 + src/istgt_log.h | 99 + src/istgt_lu.c | 4648 ++++++++++++++++ src/istgt_lu.h | 929 ++++ src/istgt_lu_ctl.c | 3474 ++++++++++++ src/istgt_lu_disk.c | 10729 ++++++++++++++++++++++++++++++++++++ src/istgt_lu_disk_vbox.c | 421 ++ src/istgt_lu_disk_xcopy.c | 600 ++ src/istgt_md5.c | 74 + src/istgt_md5.h | 49 + src/istgt_misc.c | 970 ++++ src/istgt_misc.h | 202 + src/istgt_proto.h | 287 + src/istgt_queue.c | 385 ++ src/istgt_queue.h | 73 + src/istgt_scsi.h | 337 ++ src/istgt_ser_table.c | 116 + src/istgt_sock.c | 721 +++ src/istgt_sock.h | 47 + src/istgt_ver.h | 34 + src/istgtcontrol.c | 2319 ++++++++ src/stamp-depend | 0 68 files changed, 57904 insertions(+) create mode 100644 ChangeLog.jp create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Makefile.in create mode 100644 README.md create mode 100755 config.guess create mode 100644 config.log create mode 100755 config.status create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 doc/Makefile create mode 100644 doc/Makefile.in create mode 100644 doc/QUICKSTART create mode 100644 doc/QUICKSTART.jp create mode 100644 doc/istgt.1.in create mode 100644 etc/Makefile create mode 100644 etc/Makefile.in create mode 100644 etc/auth.conf create mode 100644 etc/istgt.conf.in create mode 100644 etc/istgt.large.conf.in create mode 100644 etc/istgt.sh.in create mode 100644 etc/istgt_linux.sh.in create mode 100644 etc/istgt_netbsd.sh.in create mode 100644 etc/istgtcontrol.conf create mode 100755 install-sh create mode 100644 src/Makefile create mode 100644 src/Makefile.in create mode 100644 src/build.h create mode 100644 src/build.h.in create mode 100644 src/config.h create mode 100644 src/config.h.in create mode 100644 src/istgt.c create mode 100644 src/istgt.conf create mode 100644 src/istgt.h create mode 100644 src/istgt_cmd_table.c create mode 100644 src/istgt_conf.c create mode 100644 src/istgt_conf.h create mode 100644 src/istgt_crc32c.c create mode 100644 src/istgt_crc32c.h create mode 100644 src/istgt_iscsi.c create mode 100644 src/istgt_iscsi.h create mode 100644 src/istgt_iscsi_param.c create mode 100644 src/istgt_iscsi_param.h create mode 100644 src/istgt_iscsi_xcopy.h create mode 100644 src/istgt_log.c create mode 100644 src/istgt_log.h create mode 100644 src/istgt_lu.c create mode 100644 src/istgt_lu.h create mode 100644 src/istgt_lu_ctl.c create mode 100644 src/istgt_lu_disk.c create mode 100644 src/istgt_lu_disk_vbox.c create mode 100644 src/istgt_lu_disk_xcopy.c create mode 100644 src/istgt_md5.c create mode 100644 src/istgt_md5.h create mode 100644 src/istgt_misc.c create mode 100644 src/istgt_misc.h create mode 100644 src/istgt_proto.h create mode 100644 src/istgt_queue.c create mode 100644 src/istgt_queue.h create mode 100644 src/istgt_scsi.h create mode 100644 src/istgt_ser_table.c create mode 100644 src/istgt_sock.c create mode 100644 src/istgt_sock.h create mode 100644 src/istgt_ver.h create mode 100644 src/istgtcontrol.c create mode 100644 src/stamp-depend diff --git a/ChangeLog.jp b/ChangeLog.jp new file mode 100644 index 00000000..3fc53907 --- /dev/null +++ b/ChangeLog.jp @@ -0,0 +1,850 @@ +2012/10/28 + 2012/10/28版 + MODE_SENSEでPC=01b(Changeable values)を返すように修正 + SO_RCVLOWATとNOTE_LOWATを使うように修正 + +2012/10/16 + 2012/10/16版 + istgtcontrol:認証なしを指定するとエラーを出すのを修正 + istgtcontrol:初期化エラーで中断するように変更 + +2012/10/06 + ソケット系エラーを表示 + PDUエラー時にiqnを表示 + タイムアウトエラーログに時間を追加 + +2012/10/04 + readv/writevを使った一括処理コードを追加 + +2012/09/01 + 2012/09/01版 + サポート外のMODE_SENSEにINVALID FIELD IN CDBを返すように変更 + +2012/08/28 + 2012/08/28版 + シグナルスレッドの終了確認後にリソース解放するように変更 + +2012/08/27 + ATSで毎回mallocを発行しないよう変更 + +2012/08/24 + READ DEFECT DATA(10)/READ DEFECT DATA(12)を追加 + ダミーのATA PASS-THROUGH(16)/ATA PASS-THROUGH(12)を追加 + ダミーのLOG_SELECT/LOG_SENSEを追加 + Linuxのinitスクリプトを追加 + (Thanks to David Disseldorp) + +2012/08/21 + LUのreload時に失敗した場合は設定を戻す処理を追加 + +2012/08/19 + 処理する拡張子に qcow, qcow2, qed, vhdx を追加 + VirtualBox 4.2.X 対応 + kqueue未使用時にpoll表示を追加 + 起動時にアトミック関数の利用状況を記録 + gccビルトイン関数をconfigureで調査 + mutexの変更漏れを修正 + エラーメッセージの間違い修正 + +2012/08/13 + ダミーのシグナル関数を追加 + ループ終了コマンドの位置を変更 + +2012/08/12 + i386でgccビルトイン関数がエラーを出すので除外 + gccで警告が出る部分を修正 + +2012/08/11 + 2012/08/11版 + shutdown関数をvbox用で分離 + +2012/08/09 + 一部のmutexにADAPTIVE_NPを指定するように変更 + +2012/08/08 + VirtualBoxの共有ライブラリを使った仮想ドライブに対応 + +2012/08/07 + 2012/08/07版 + 転送ロック位置を修正 + タスクバッファー割り当てサイズを追加 + エラー時の処理忘れを修正 + +2012/08/06 + リロード回数をログに残すように修正 + リロード時のエラーを続行できるように修正 + NetBSDのEV_SET警告を修正 + gcc4.1以降のビルトイン関数を使った状態取得関数を追加 + 不要な変数関数などを整理 + 終了時のメモリーリークを修正 + LUNキューが複数ある場合は1ループで2回実行するように変更 + +2012/08/05 + LUの変更処理(接続中を除く)を追加 + キュー内の要素数を保持するように修正 + キューのロック時間を削減 + アクセス不可のPGをSendTargetsで出さないように修正 + +2012/07/29 + PG設定エラー時にループを抜けないように変更 + SIGTERM/INT受信時にacceptループに停止要求を発行 + 終了時に全コネクションスレッドに停止要求を発行 + +2012/07/28 + 終了時の状態をロックなしで行うように変更 + NetBSD用のスクリプトを追加 + 起動スクリプトにBEFORE: LOGIN、REQUIRE: syslogd mountlateを追加 + configure.in/Makefile.inを修正 + clangとgccで警告が出る部分を修正 + -Wextra -Wformatなどコンパイラの警告を追加 + +2012/07/26 + 2012/07/26版 + スレッド実行順序によりクラッシュする問題を修正 + 余分なcloseを発行している部分を削除 + reservationの登録/削除で誤ったキーを操作する問題を修正 + +2012/07/25 + 2012/07/25版 + PGの追加、削除、変更処理を追加 + PG処理をIG同様の形式に変更 + トップレベルの状態mutexを導入 + メモリ解放エラーを修正 + サンプルのauth.confの認証設定をコメントアウト + poll待ち時間を5000msに変更 + +2012/07/24 + デーモン時のコネクションkqueueでシグナルを処理しないように変更 + シンボリックデバイスを許可するconfigureオプションを追加 + kqueue使用時はログに記録するように追加 + シグナルスレッド連絡用のパイプを追加 + istgt終了処理の関数を作成 + 起動スクリプトを修正 + マニュアルインストール先を決め打ちしないように修正 + FreeBSD以外はrcファイルをコピーしないように修正 + +2012/07/23 + 0.5系として分離 + clang -O3を最優先で利用するように変更 + Linuxで_GNU_SOURCEを設定するように修正 + SIGHUPで設定ファイルをリロードするように処理を追加 + LUの追加、削除、IGの追加、削除、変更処理を追加 + PGとIGに参照カウンタを追加 + 起動スクリプトからBEFOREキーワードを削除 + +2012/07/22 + 各MakefileにPHONYターゲットを追加 + 初期状態の設定をロックなしで実行するように修正 + ファイルオープンエラーを表示するように修正 + (Thanks to Serge) + +2012/01/24 + StatSN, ExpCmdSN, MaxCmdSN を送信スレッドで設定するよう修正 + +2012/01/22 + デフォルトパラメータ調整 + LUN最大定義数を64に変更 + clangで警告が出ないように修正 + +2011/12/14 + StatSNの処理をmutex内に移動 + +2011/12/11 + 送信エラー発生時に即座に受信スレッドを起こすように修正 + --as-neededを追加できるようにMakefileを修正 + (Thanks to Julian Taylor) + +2011/10/08 + 2011/10/08版 + ノーマルセッション中のSendTargetsの応答を追加 + F_SETFLのエラーを出さないよう修正 + +2011/10/02 + リードキャッシュ、ライトキャッシュのダミー設定を追加 + 文字列の比較をstrcasecmpに統一 + ロック期間・範囲の調整 + +2011/09/28 + 2011/09/28版 + NetBSDのアトミックプリミティブに対応 + COMPARE AND WRITEをtraditionalで未定義に変更 + 動作モードにnormalを追加してデフォルトに設定 + ブロック数の計算で符号つき無しを統一 + +2011/09/26 + LUNキューの処理方法を修正 + ATSの比較エラーを表示しないように変更 + 送信スレッドにタイムアウトを設定 + 結果キューの初期化・終了忘れを修正 + +2011/09/24 + 状態チェックのロックをアトミック命令に変更 + +2011/09/18 + 2011/09/18版 + グループの最大数を1024から4096に変更 + +2011/09/13 + デーモン化前に出力フラッシュを追加 + WRITE_SAMEの転送済みサイズの間違いを修正 + WRITE_SAMEを複数ブロックまとめて処理するように変更 + 作業用サイズのマクロ名を変更 + Makefileで-Cを使わないように変更 + (Thanks to Stephen Borrill) + +2011/09/07 + 2011/09/07版 + ターゲット名のチェックを強化 + COMPARE AND WRITEを実装 + EXTENDED COPYのダミー処理を追加 + VPDデータを修正 + +2011/09/05 + LUN毎の回転数(RPM)、形状(FormFactor)設定を追加 + LUN毎のシリアル設定を追加(デフォルト値は id+"L"+LUN番号) + WRITE_SAMEの最大LBAチェックを先に実行するよう変更 + +2011/09/02 + 2011/09/02版 + WRITE_SAME(10)/WRITE_SAME(16)を実装 + +2011/08/31 + Block Length に256KBと512KBを追加 + Thin Provisioning関連のダミーを追加 + Block Limits と Block Device Characteristics のVPDを追加 + TargetAddress を Discovery でのみ返すように変更 + AIOの処理を削除 + +2011/08/22 + configのパスを修正 + AIOが無効の場合は sigwaitinfo を使わないように差し戻し + PATH_MAXがない場合を考慮するように変更 + Makefileで下層の処理エラーを反映するように変更 + DESTDIRを処理するように変更 + (Thanks to Arno Toell) + +2011/07/17 + 2011/07/17版 + 全イニシエータ拒否の指定!ALLを追加 + 無指定時のQueueDepthを32に変更 + O_FSYNCがない場合はO_SYNCを指定するように変更 + スレッドスタックサイズを2MBに変更 + +2011/07/03 + イニシエータ指定で!を先頭につけると拒否する機能を追加 + 初期ファイルサイズを最少サイズで割り当てるように変更(-m1) + ファイルの範囲外で全てゼロの場合は書き込みスキップに変更(-m1) + ロックおよび初期化位置を修正 + AIOを使った書き込み処理を追加(デフォルトOFF) + Discoveryセッションで処理するべきでないキーを追加 + +2011/05/29 + 2011/05/29版 + マルチセッションの時にキューが不足する問題を修正 + R2Tの処理にmutexを追加 + ダミーの送信ソケット追加 + 送信スレッドに強制中断チェックを追加 + 初期定義ファイルで InitiatorName "ALL" を設定 + 起動スクリプトに reload を追加 (ports/156117) + +2011/02/23 + 2011/02/23版 + 特定環境でメモリリークする問題を修正 + +2011/02/19 + 2011/02/19版 + 全スレッドにスレッド属性を適用するように修正 + +2011/02/18 + 10Gbpsで期待通りにパフォーマンスが伸びない問題を修正 + スレッドロックを改良 + +2011/01/14 + プロトコルスレッドのスタックサイズを2MBから4MBに変更 + スレッドロックを改良 + +2011/01/03 + 2011/01/03版 + 0.4系として独立 + ISTGT_DISABLE_SENDER_THREADの設定を削除 + 動作モードを変更するスイッチを追加(デフォルトは20100707互換) + ダイジェスト機能を有効にしていると接続できない問題を修正 + +2011/01/02 + 2011/01/02版 + シーケンシャル書き込みの結果を送信スレッドに渡すように変更 + ISTGT_DISABLE_SENDER_THREADをistgt_iscsi.cで定義する事で + 送信スレッドの作成を行わない従来モードになるように追加 + MaxOutstandingR2Tの設定より多いR2Tを先送りしないように変更 + メモリ解放をキュー実行直後にするように変更 + +2011/01/01 + シーケンシャル書き込みが送信スレッドにブロックされないよう修正 + +2010/12/30 + 2010/12/30版 + SCSI応答のループ外でロックをするように変更 + 各PDU毎のメモリ割り当て回数を削減 + DATA-OUTを使わない応答は送信スレッドに直接渡すように変更 + PDU送信スレッドを追加 + デフォルトのウィンドウサイズを8に変更 + PDU書き込み中に分断されないようにロック取得するように修正 + 接続情報のtypoを修正 + (Thanks to Kevin Day) + +2010/07/07 + 2010/07/07版 + DefaultTime2Waitの比較を最大値を取るように修正 + ターゲットが存在しない場合に検索した記録を残すように修正 + デバッグ用のトレースを追加 + errno比較の定数をシンボルに置換 + istgt_dumpが不要な戻り値を返すのを修正 + +2010/06/06 + 2010/06/06版 + NO_R2T_PRESENDの定義を廃止(設定ファイルで無効化できる為) + トレースモードでない場合はPDU実行前後のロックを取らないように変更 + 状態ロック範囲をグローバルから各ターゲット毎に変更 + +2010/06/05 + 各ターゲット毎にローカル設定を持てるように設定を追加 + +2010/06/04 + InitialR2T, ImmediateData, DataPDUInOrder, DataSequenceInOrder, + ErrorRecoveryLevel の設定を追加 + +2010/06/01 + LUNリセット時にファイルの再オープンをするように変更 + リソース不足のエラー抜けを追加 + パラメータ長の不足を修正 + +2010/05/27 + SCSI応答のエラーにもイニシエータ及びターゲットポート表示を追加 + +2010/05/25 + 2010/05/25版 + F_Bitの処理が抜けているのを修正 + ショートパケットの解放間違いを修正 + TL>FB+MBの条件下で追加のR2Tが送信されない問題を修正 + +2010/05/22 + 2010/05/22版 + 8KB, 16KB, 32KB, 64KB, 128KBの論理ブロック長を追加 + 認証なしを強制するオプションを追加(AuthMethod None) + readキャッシュの状態をMODESENSEで返すように追加 + kqueueのクリーンナップ処理を追加 + configureのバージョンを更新 + インデントと折り返しを修正 + cmd_queueのロック忘れを修正 + 予約ポートの解放忘れを修正 + +2010/05/21 + 2010/05/21版 + WRITEコマンドで先送りするR2T最大数の設定を追加(省略時 MaxR2T=16) + +2010/05/20 + エラー時にイニシエータ及びターゲットポートを表示するように修正 + 8KB以下のショートパケットにデータ領域を作成しないように変更 + 終了処理で実行中タスクの解放を行うように変更 + ソケットlistenのバックログを10から2に変更 + +2010/05/16 + 2010/05/16版 + MaxOutstandingR2T, DefaultTime2Wait, DefaultTime2Retain の設定を追加 + R2Tの送信・処理を平行できるように修正 + R2Tが必要な場合はキューイング前に送出するように変更 + (istgt_iscsi.c の NO_R2T_PRESEND を定義する事により無効) + ESXiのイニシエータ利用を想定したデフォルト値に変更 + 初期データおよびセンスデータのメモリ割り当てを先に実行するように修正 + syslog priority のデフォルトを notice から info に変更 + +2010/05/15 + 0.2ブランチを作成 + 乱数生成に arc4random を利用するように修正 + Read/Writeキャッシュの状態を保存するように修正 + シグナルスレッドの終了を待つように修正 + メインスレッドにスレッド名を付けるように修正 + copy_pdu, srandom, arc4random 関数を外部リンケージに変更 + logout関数でセッションポインタをチェックするように修正 + configポインタのクリア位置を修正 + +2010/04/07 + 2010/04/07版 + NetBSD, Mac OS X, Linuxなどブロック型のサイズも取得するように修正 + Auto sizeエラーの場合に対象ファイルも表示するように修正 + トレース中のみデバイスサイズ取得時の失敗を出すように修正 + トレース中のみ重複予約に対して警告を出すように修正 + /usr/local/をヘッダに埋め込まないように修正 + 利用していないコンフィグファイルを読まないように修正 + デフォルトノード名を iqn.2007-09.jp.ne.peach.istgt に変更 + デフォルトベンダ名をOS毎に指定するように修正 + 認証ファイルのデフォルトパスを修正 + +2010/02/19 + エラー表示が正しくされないのを修正 + +2010/01/25 + 2010/01/25版 + シリアル番号生成機能を一時無効に修正 + pthread_set_name_npでスレッド名をつけるように修正 + (Thanks to Ivan Voras) + +2010/01/22 + NodeBase名からシリアル番号を生成するように修正 + 実行待ちタスクをエラー中断できるように修正 + クリーンナップ処理で条件待ちにabortを返すように修正 + スレッド条件待ち時間の最小を5秒に修正 + +2010/01/12 + 2010/01/12版 + テープとチェンジャーのタイムアウト値を修正 + 固定フォーマットの場合は正確にあわせるように修正 + センスデータ長の間違いを修正 + +2010/01/11 + MMCデバイスにMODESENSE(6)を発行しないように修正 + パススルーでBlockDescriptorがない場合に誤動作するのを修正 + istgtcontrol:setproctitle がない場合の処理を修正 + +2010/01/05 + 2010/01/05版 + uctl: パススルーデバイスを出力するように修正 + uctl: LUNタイプを出力するように修正 + configure.inを現行ソースに合わせて修正 + パススルーでMODESENSE(6)エラー時に(10)を再実行できるように修正 + istgtcontrol:verboseモードを追加して既存コードを移動 + istgtcontrol:プロセスタイトルにバージョンを表示するように修正 + +2010/01/04 + MediaDirectoryの中にないメディアへの交換を拒否するように修正 + 設定ファイルにMediaDirectoryを追加 + テープ作成前に制御ブロックが破損していないか検査するように修正 + クローズ処理が必要ない場合はすぐ戻るように修正 + 全書き込みビットがないファイルを読み込み専用と認識するように修正 + メディア自体の読み込み属性表示を追加 + 書き込みできないメディアファイルに読み込み専用フラグを追加 + istgtcontrol: AuthMethod Autoの処理を改善 + istgtcontrol: 認証ユーザとシークレットを指定可能に修正 + +2010/01/02 + /dev/nullのメディアを空スロットと認識するように修正 + メインスレッドでコネクションスレッド終了を少し待つように修正 + 明示して変数を初期化するように修正 + COPYRIGHT表記を修正 + +2009/12/27 + kqueue/keventを利用するように修正 + ソケットタイマーを常時設定するように修正 + ソケット入出力の呼び出し関数を変更 + 関数呼び出しを削減するように修正 + +2009/12/25 + 2009/12/25版 + CAMタイムアウトを修正 + パススルーでMODESENSEに失敗する場合でも通過するように修正 + TargetNameがiSCSI名規則に合致するか確認するように修正 + 関数呼び出しを減らすようにマクロ追加など修正 + FirstBurstLengthとMaxBurstLengthはコピーを持つように修正 + +2009/12/22 + 2009/12/22版 + デフォルトのキューサイズを32に変更 + +2009/12/20 + エラー時の処理抜けを修正 + エラーメッセージの表示間違いを修正 + syslogプライオリティをコンパイル時に指定できるように修正 + 高負荷時に問題を起こすので以前の処理に変更 + +2009/12/19 + ナノ秒指定になっていなかったのを修正 + 待ち時間を増加、タイムアウト値と連動するように修正 + タスクの処理開始時間を記録するよう修正 + ベンダ定義VPDをエラーから警告に修正 + Task管理でStatSNの更新をしないように修正 + ポインタキャストの警告を修正 + +2009/12/18 + 2009/12/18版 + syslogファシリティをコマンドラインで指定できるように追加 + +2009/12/16 + Logoutパケットでエラーを出さないように修正 + StarPortのExpStatSNエラーの回避策を追加 + 最大ユニット数、イニシエータ・ポータルグループ数を増加 + セッションテーブルを最大ユニット数で確保するように修正 + PIDの書き込み前及び終了時にpidfileを削除するように修正 + Autoサイズのエラーを表示するように修正 + +2009/12/11 + 2009/12/11版 + CAMエラー時の処理を上層に引き渡すように修正 + CAM呼び出しのデフォルトタイムアウト値を修正 + PASS型のセンスデータの応答ずれを修正 + PASS型のバージョンチェックが通らないのを修正 + PASS型でチェンジャーデバイスを見るように修正 + PASS型で4KB境界調整を行うように修正 + DVD/TAPE型でREQUEST_SENSEの応答データずれを修正 + ディスク型でREQUEST_SENSEに応答するように修正 + +2009/12/03 + セッション強制終了の前に少し待機するように修正 + セッション検索時に初期値をいれるように変更 + ソケット読み出しを優先するように変更 + +2009/11/30 + 2009/11/30版 + ショートサイズ判定を4Kから8Kに変更 + TAPE型のメディア変更が正しく扱えない問題を修正 + 警告ログを抑制するオプションを追加 + 接続リセットとタイムアウトのイニシエータを記録するように修正 + DATA-OUT時にLUNフィールドをチェックしないように修正 + PDU読み込み失敗時に未初期化状態になるのを修正 + +2009/11/24 + 2009/11/24版 + StatSNのチェックにキューサイズを考慮するように修正 + PDUエラーで接続リセットとタイムアウトを表示するように修正 + PDU書き込みエラー番号を記録するように修正 + 書き込み処理中のR2Tの追加発行を行うように修正 + NOPOUTのIビットをチェックするように修正 + SCSI2互換LUN予約解放でイニシエータ名を考慮するように修正 + +2009/11/12 + 2009/11/12版 + デフォルトのコンパイルフラグを修正 + デフォルトのキューサイズを20に変更 + エラーメッセージの変更 + +2009/09/08 + シリアル番号演算のマクロ展開が正しく行われない問題を修正 + シリアル番号に減算をしないように修正 + +2009/04/30 + AI_NUMERICSERVがない環境の場合は0を想定するように修正 + configureのチェックライブラリを修正 + +2009/04/29 + パススルーでatapicamを考慮するように修正 + +2009/04/28 + 2009/04/28版 + 接続情報の取得時にマルチ接続を正しく扱えない問題を修正 + シリアル番号演算を適用するように修正 + キューイング数の計算を間違えていたのを修正 + セッションロックの二重UNLOCKを削除 + +2009/04/27 + 2009/04/27版 + キューイングによりセンスデータが破壊される問題を修正 + 不要になった変数を削除 + +2009/04/25 + 2009/04/25版 + MCSの逆順チェックを条件変数でチェックするように修正 + PDUの読み出し前にコピーフラグを消すように修正 + 双方向入出力のSCSIコマンドにエラーを出すように修正 + DATA-OUTのエラー処理を修正 + DATA-OUTが完了したら処理を切り離すように修正 + 実行中のタスク完了を待って終了するように修正 + +2009/04/24 + 保留したコマンドを再投入時にイベントを消去するように修正 + RejectコマンドでExpCmdSNとMaxCmdSNが増加しないように修正 + 以前のソケットI/Oルーチンを利用するように修正 + +2009/04/22 + 2009/04/22版 + TSIHを期待通りに解放していない問題を修正 + readループを利用するように変更 + pollの待ち時間を3000msに変更 + cond_waitの待ち時間を30sに変更 + MCS逆順の待ち時間を10000msに変更 + DATA-OUTのLUNチェックをエラーから警告に変更 + +2009/04/20 + 2009/04/20版 + ブロッキングモードのread/writeを利用するように修正 + コマンドキューが有効な時はExtended INQUIRYに反映するように修正 + サンプル定義ファイルのキューの深さを32に変更 + FFPの移行がDiscoveryセッションであるか調べるように修正 + ソケットエラーの場合はerrnoをログに記録するように修正 + +2009/04/16 + 2009/04/16版 + R2TにLUNを載せていなかったのを修正 + AC_SYS_LARGEFILEをテストするように修正 + シンボリックリンクに対するサイズ取得は実行しないように修正 + RAWデバイスに対してもAutoサイズで割り当てるように修正 + 既存のファイルを壊さないで作成するように修正 + ターゲットの接続情報を取得するINFOコマンドを追加 + istgtcontrol: INFOコマンド対応 + +2009/04/14 + 20090414版 + READ(6)/WRITE(6)のLBA上位5ビットが欠落する問題を修正 + +2009/04/12 + 20090412版 + データ設定取得マクロを関数呼び出しからマクロ展開コードに変更 + ショートサイズの判定に誤ったマクロを利用していたのを修正 + ショートサイズ送信機能を有効にするマクロ定義を追加 + Sビットが有効な時にのみオバー/アンダーフローを返すように修正 + Discoveryセッションは最大接続数を1に制限するように修正 + NOPOUTの返答データを最小サイズに制限するように修正 + DATAOUTで各種パラメータの有効性を確認するように修正 + NOPIN間隔が0の場合は送信しないように修正 + ソケットI/Oのリトライ位置を変更 + 8192バイト未満のバッファサイズは割り当てないように修正 + syslogファシリティを設定ファイルで指定できるように追加 + +2009/03/26 + 20090326版 + 無効なLUNに対するエラーログを出さないように修正 + リセット処理でLUをチェックするように修正 + タスク管理コマンドでキューをクリアするように修正 + +2009/03/25 + ワイルドカードアドレスを接続IPに変換するように修正 + istgtcontrol: iqn指定がALLの場合の処理を追加 + タスク数の定数をマクロ定義に変更 + タスクをコネクションデータに保存するように修正 + タスク実行時のエラーをチェックできるように修正 + LUNライト前に保留PDUが次のCmdSNならキューに投入するように修正 + エラー時のデッドロック回避を行うように修正 + +2009/03/23 + 20090323版 + LUNスレッドの起動順序が正しくないのを修正 + dumpデータを一行単位で一括して出力するように修正 + +2009/03/22 + タイムアウト値を修正 + +2009/03/21 + トレースログ関数の呼び出し前にフラグチェックするように修正 + リセット処理でLUNタイプをチェックするように修正 + pthread系などの戻り値チェックを間違えていたのを修正 + mutexの不要なunlock呼び出しを修正 + PDUデータのコピー処理を追加 + 終了要求されたかどうかPDU受信毎にチェックするように修正 + +2009/03/20 + キューサイズを調整できるように設定を追加 + 小さいPDUはヘッダとデータ部分を一緒にwriteするように修正 + 保留PDUの後にエラーが発生した場合にfreeしてしまう問題を修正 + +2009/03/19 + AHSのサイズ計算を間違えていたのを修正 + MCSでCmdSNが逆順に到着した場合の待機時間を200msから1000msに変更 + ロック期間を短くするように調整 + iqn.以外にeui.とnaa.も完全指定を許可するように変更 + +2009/03/18 + コネクション単位のSCSIセンス用データ領域を64Kから4Kに縮小 + 仮想テープで終了時のメモリサイズ指定、解放忘れを修正 + コネクション単位の固定バッファからコマンド単位の固定または + 動的バッファを利用するように修正 + セッションデータ用のmutex_destroyを呼び出していないのを修正 + LUの終了時にエラー停止する可能性があったのを修正 + コネクション生成削除用ロックなどのトレースメッセージを追加 + LU RESETが発生した場合に自分の接続は消滅しないように修正 + SIGRTMIN+XXもしくはSIGIOによるシグナル配送に対応 + +2009/03/17 + トレースログでログイン、ログアウトが二重に表示されるのを修正 + MaxSessionsとMaxConnectionsに0が指定できた問題を修正 + 再接続時にMaxConnectionsを超えるコネクションが存在する場合は + 強制終了を試みるように変更 + キューイング処理用LUNスレッドを追加 + ディスク型にコマンドキューイングする場合の処理を追加 + MCSでCmdSNが逆順に到着した場合の待機時間を100msから200msに変更 + +2009/03/15 + docディレクトリを常時作成していたのを修正 + mkdepがない場合でもバイナリ作成できるように修正 + +2009/03/14 + 20090314版 + 同一のポータルタグ、イニシエータからMCS接続を複数した場合に + セッションを間違える問題を修正 + CAMライブラリが存在しない環境はパススルー処理しないように修正 + NetBSDにない関数を置き換えるように追加 + 移植に問題を起こしそうな部分を修正 + セッションロックのミスを修正 + +2009/03/13 + 20090313版 + パススルーでシーケンシャルデバイスをサポートするように追加修正 + トレース用メッセージの修正 + CAMエラー処理が正しくないのを修正 + +2009/03/09 + 20090309版 + MRDSを指定しないイニシエータを考慮するように修正 + 設定ファイルで指定しない場合のデフォルトの値を調整 + NOPIN間隔を調整できるように追加 + トレース用ダンプを標準エラー出力に変更 + 正常ログインもsyslogに記録するように修正 + +2009/03/08 + 20090308版 + パススルーはサポート外コマンドでも渡すように修正 + MRDS > FB の状態でPDUを正しく受信できない問題を修正 + NOPOUTが予期しないStatSNエラーになる問題を修正 + 保留するコマンドキューに制限がなかった問題を修正 + PROでSPEC_I_PTの扱いが適切でない問題を修正 + PROでキーの登録数をチェックしていない問題を修正 + ディスク型はUNIT ATTENTION(POWER ON, RESET)を発行するように追加 + TargetAliasが無い時の動作が期待通りでないので修正 + +2009/03/07 + パススルーでFirstBurstに乗らないRW以外のデータも扱えるように修正 + 初期化時にUNIT ATTENTIONを返した場合にリトライするように修正 + 初期化時に媒体容量をチェックするように追加 + サポート外ユニットにINQUIRY以外発行しないように修正 + パススルーでDVDROMデバイスをサポートするように追加修正 + +2009/03/06 + 20090306版 + 再投入するデータを戻し忘れてクラッシュする問題を修正 + 消失したと思われるコマンドを読み飛ばすように修正 + ダイレクトアクセス型のパススルーデバイスを追加 + +2009/03/04 + 20090304版 + LU初期化時にActive/optimizedを初期値とするように変更 + Task Managementの処理はパケット消失に備えてCmdSN/StatSNをリセット + するように修正 + データ転送時のDATAOUTパケット以外を転送終了後に再投入するように修正 + INQUIRYのTPGSをサポートなしに修正 + +2009/03/03 + StatSNの管理を次に送信するべき値を保持するように修正 + 仮想DVDROM、仮想テープもディスク型と同様のINQUIRYに修正 + マルチパスで複数のPDUを許可するように暫定処理を追加 + +2009/03/02 + NAA形式のINQUIRYも出力するように修正 + 標準INQUIRYのHISUPビットをセットするように修正 + アイドル時にNOPINコマンドを発行するように追加 + TargetAliasが存在しない場合も送信していた問題を修正 + SIGINFOを捕捉するように修正 + +2009/03/01 + 20090301版 + Discoveryセッションで接続ポートからLUにアクセス可能か調べるように修正 + Extension Keyをエラーログに残さないように修正 + AuthMethod Noneを廃止してAutoを追加 + GB表示の媒体サイズを少数第一位まで表示するように修正 + +2009/02/28 + 20090228版 + パラメータチェックの前にコピーしていた問題を修正 + Declarativeパラメータを送信しないように修正 + NOPOUT応答時にStatSNを進めないように修正 + INQUIRY VPD 0x85/0x87/0x88に応答するように追加 + ロジカルユニットが無い場合はポータルタグを送信しないように修正 + エミュレート応答が期待通りに動かないのを修正 + +2009/02/27 + 20090227版 + イニシエータ、イニシエータポート、ターゲット、ターゲットポートを + それぞれ小文字に変換した値を保持するように修正 + PRO REGISTER/PREEMPT AND ABORTを実装 + PRI REPORT CAPABILITIES/READ FULL STATUSを実装 + Disk型のRELEASE(6)/RELEASE(10)/RESERVE(6)/RESERVE(10)を + エミュレート応答に修正 + +2009/02/26 + 認証用データの解放忘れを修正 + PERSISTENT RESERVE INとPERSISTENT RESERVE OUTに応答するように追加 + PRI READ KEYS/READ RESERVATIONを実装 + PRO RESERVE/RELEASE/PREEMPT/REGISTER AND IGNORE EXISTING KEYを実装 + PRO CLEARを実装 + 各SCSIコマンドで影響を受ける場所にチェックポイントを追加 + +2009/02/24 + REPORT LUNSのCDBチェックを行うように修正 + 接続したポータルインデックスの初期化忘れを修正 + 接続したポータルグループ及びロジカルユニットグループをINQUIRYに追加 + REPORT TARGET PORT GROUPSに応答するように追加 + 接続のないLUNにアクセスした場合にクラッシュする問題を修正 + ロジカルユニットの最大タグ値のチェック忘れを修正 + immediateにマークされたPDUに対してCmdSNを進めてしまっていたのを修正 + リセットが発生した場合はイニシエータの全コネクションに対して停止を + するように修正 + MODE SELECTの長さ0とヘッダに満たない特殊なケースを処理するように修正 + SET TARGET PORT GROUPSに応答するように追加 + +2009/02/23 + 20090223版 + Securityステージを実行しないイニシエータと接続できない問題を修正 + StatSNの初期化忘れを修正 + prefix等をサンプル設定及び起動スクリプトファイルに反映するように修正 + 関数名の変更もれを修正 + +2009/02/22 + istgt初期リリース(20090222版) + MSC Extraパッチのコンセプトを元に新規に処理ルーチンを書き直しました + 複数ポータル、複数グループ、FreeBSD7.xとZFS用をコンセプトにしています + +intgt以前の主要な変更点 +2009/01/25 + 20090125版 + Windows7ベータ版によるディスクレスブートでの問題を修正しました + ステータスシーケンス番号エラーを修正しました +2009/01/22 + 20090122版 + 仮想ディスクのロック方式を仮想DVDROMと仮想テープに合わせました + 一部のiSCSIブート機能に対応しました +2009/01/17 + 20090117版 + 仮想DVDROM及び仮想TAPE(DLT8000)エミュレータを追加しました + サイズの加減算表記を追加しました + メディア制御機能istgtcontrolを追加しました +2008/12/25 + 20081225版 + MODESENSEのライトキャッシュの状態をO_FSYNCに反映するようになりました + シグナル処理スレッドを新設しました + SIGTERM/STGINTに対して終了処理を行うように修正しました +2008/12/23 + 20081223版 + パッチ量が多くなった為にMCSパッチからMCS Extraパッチと呼称変更しました + 初期版から搭載していたMCS簡易同期機能を廃止した + 管理テーブルを活用するようになった +2008/12/21 + 20081221版 + 64bitLBAに対応した + Discoveryセッションにも認証を強制できるようになった + 認証ファイル、PIDファイルを個別に指定できるようになった + サイズサフィックスにZEPも追加した +2008/12/18 + 20081218版 + CHAP相互認証機能を追加しました +2008/12/17 + 20081217版 + 認証、ダイジェストの強制モードを追加しました + SCSIステータスを最終PDUに載せるようになりました +2008/12/11 + 20081211版 + バグフィックス +2008/12/05 + 20081205版 + コネクションスレッド制御用の管理テーブルを作成しました + 排他ロック範囲を当該スレッドに限定するように変更しました + データ及びヘッダダイジェスト機能(CRC32C)をサポートしました +2008/12/02 + 20081202版 + マルチセッション用にmutexによる排他ロック制御を導入しました +2008/11/30 + 20081130版 + バグフィックス +2008/11/29 + 20081129版 + バグフィックス +2008/11/18 + 20081118版 + 初期リリース + ports/net/iscsi-target(netbsd-iscsi-20080207)を元にMCSパッチを + 作成しました diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..cc156fcf --- /dev/null +++ b/INSTALL @@ -0,0 +1,28 @@ + +1) run configure script + +# ./configure + +2) build & install binary and sample configuration files + +# make +# make install +# make install-doc + +3) create your configuration files and edit it +for more detail, see /usr/local/share/doc/istgt/QUICKSTART + +# cd /usr/local/etc/istgt +# cp auth.conf.sample auth.conf +# cp istgt.conf.sample istgt.conf +# cp istgtcontrol.conf.sample istgtcontrol.conf +# EDIT files + +4) start daemon + +# /usr/local/etc/rc.d/istgt forcestart + +5) edit /etc/rc.conf to run it at startup + +istgt_enable="YES" + diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..5ba9549c --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Copyright (C) 2008-2012 Daisuke Aoyama . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..af309b72 --- /dev/null +++ b/Makefile @@ -0,0 +1,95 @@ +# top Makefile + +top_srcdir = . +srcdir = . + +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +sysconfdir = ${prefix}/etc +datarootdir = ${prefix}/share +datadir = ${datarootdir} +libexecdir = ${exec_prefix}/libexec +mandir = ${datarootdir}/man + +PACKAGE_NAME = istgt +PACKAGE_STRING = istgt 0.5 +PACKAGE_TARNAME = istgt +PACKAGE_VERSION = 0.5 + +document = COPYRIGHT README INSTALL ChangeLog.jp + +VER_H = src/istgt_ver.h +DISTBASE = istgt +DISTVER = `sed -e '/ISTGT_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +DISTEXTVER = `sed -e '/ISTGT_EXTRA_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +#DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) +#DISTDIR = $(DISTBASE)-$(DISTVER)-$(DISTEXTVER) +DISTDIR = $(DISTBASE)-$(DISTEXTVER) +DISTNAME = $(DISTDIR).tar.gz +DISTFILES = Makefile.in configure.in config.guess config.sub install-sh configure \ + $(header) $(source) $(ctl_header) $(ctl_source) \ + $(document) $(sample) + +SUBDIRS = src etc doc + +######################################################################### + +.PHONY: all install install-doc +all: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +install: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +install-doc: + for subdir in doc; do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + + +.PHONY: dist clean distclean local-clean local-distclean depend +dist: distdir + rm -rf $(DISTDIR) $(DISTNAME) + mkdir $(DISTDIR) + for file in $(DISTFILES); do \ + cp -p $(srcdir)/$$file $(DISTDIR); \ + done + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) subdir=$$subdir $@) || exit $$?; \ + done + tar cf - $(DISTDIR) | gzip -9c > $(DISTNAME) + rm -rf $(DISTDIR) distdir + +distdir: + echo $(DISTDIR) >$@ + +clean: local-clean + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +distclean: clean local-distclean + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +local-clean: + -rm -f a.out *.o *.core + -rm -f *~ + +local-distclean: local-clean + -rm -f Makefile config.status config.cache config.log config.h + -rm -f $(DISTNAME) distdir + +depend: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +######################################################################### diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..5d44d786 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,95 @@ +# top Makefile + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +libexecdir = @libexecdir@ +mandir = @mandir@ + +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ + +document = COPYRIGHT README INSTALL ChangeLog.jp + +VER_H = src/istgt_ver.h +DISTBASE = istgt +DISTVER = `sed -e '/ISTGT_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +DISTEXTVER = `sed -e '/ISTGT_EXTRA_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +#DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) +#DISTDIR = $(DISTBASE)-$(DISTVER)-$(DISTEXTVER) +DISTDIR = $(DISTBASE)-$(DISTEXTVER) +DISTNAME = $(DISTDIR).tar.gz +DISTFILES = Makefile.in configure.in config.guess config.sub install-sh configure \ + $(header) $(source) $(ctl_header) $(ctl_source) \ + $(document) $(sample) + +SUBDIRS = src etc doc + +######################################################################### + +.PHONY: all install install-doc +all: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +install: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +install-doc: + for subdir in doc; do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + + +.PHONY: dist clean distclean local-clean local-distclean depend +dist: distdir + rm -rf $(DISTDIR) $(DISTNAME) + mkdir $(DISTDIR) + for file in $(DISTFILES); do \ + cp -p $(srcdir)/$$file $(DISTDIR); \ + done + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) subdir=$$subdir $@) || exit $$?; \ + done + tar cf - $(DISTDIR) | gzip -9c > $(DISTNAME) + rm -rf $(DISTDIR) distdir + +distdir: + echo $(DISTDIR) >$@ + +clean: local-clean + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +distclean: clean local-distclean + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +local-clean: + -rm -f a.out *.o *.core + -rm -f *~ + +local-distclean: local-clean + -rm -f Makefile config.status config.cache config.log config.h + -rm -f $(DISTNAME) distdir + +depend: + for subdir in $(SUBDIRS); do \ + (cd $$subdir; $(MAKE) $@) || exit $$?; \ + done + +######################################################################### diff --git a/README.md b/README.md new file mode 100644 index 00000000..e69de29b diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..0e30d56e --- /dev/null +++ b/config.guess @@ -0,0 +1,1407 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-07-02' + +# This file 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/FreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.log b/config.log new file mode 100644 index 00000000..24a73582 --- /dev/null +++ b/config.log @@ -0,0 +1,2965 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by istgt configure 0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ ./configure + +## --------- ## +## Platform. ## +## --------- ## + +hostname = dev +uname -m = x86_64 +uname -r = 4.13.0-36-generic +uname -s = Linux +uname -v = #40~16.04.1-Ubuntu SMP Fri Feb 16 23:25:58 UTC 2018 + +/usr/bin/uname -p = unknown +/bin/uname -X = unknown + +/bin/arch = unknown +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +/usr/bin/hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: /home/payes/bin +PATH: /home/payes/.local/bin +PATH: /usr/local/sbin +PATH: /usr/local/bin +PATH: /usr/sbin +PATH: /usr/bin +PATH: /sbin +PATH: /bin +PATH: /usr/games +PATH: /usr/local/games +PATH: /snap/bin +PATH: /usr/local/go/bin +PATH: /home/payes/gocode/bin +PATH: /home/payes/.fzf/bin + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:2438: checking for clang +configure:2454: found /usr/bin/clang +configure:2465: result: clang +configure:2496: checking for C compiler version +configure:2505: clang --version >&5 +clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final) +Target: x86_64-pc-linux-gnu +Thread model: posix +InstalledDir: /usr/bin +configure:2516: $? = 0 +configure:2505: clang -v >&5 +clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final) +Target: x86_64-pc-linux-gnu +Thread model: posix +InstalledDir: /usr/bin +Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/6.0.0 +Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0 +Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/6.0.0 +Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/6.0.0 +Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/5.4.0 +Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.0.0 +... rest of stderr output deleted ... +configure:2516: $? = 0 +configure:2505: clang -V >&5 +clang: error: argument to '-V' is missing (expected 1 value) +clang: error: no input files +configure:2516: $? = 1 +configure:2505: clang -qversion >&5 +clang: error: unknown argument: '-qversion' +clang: error: no input files +configure:2516: $? = 1 +configure:2536: checking whether the C compiler works +configure:2558: clang conftest.c >&5 +configure:2562: $? = 0 +configure:2610: result: yes +configure:2613: checking for C compiler default output file name +configure:2615: result: a.out +configure:2621: checking for suffix of executables +configure:2628: clang -o conftest conftest.c >&5 +configure:2632: $? = 0 +configure:2654: result: +configure:2676: checking whether we are cross compiling +configure:2684: clang -o conftest conftest.c >&5 +configure:2688: $? = 0 +configure:2695: ./conftest +configure:2699: $? = 0 +configure:2714: result: no +configure:2719: checking for suffix of object files +configure:2741: clang -c conftest.c >&5 +configure:2745: $? = 0 +configure:2766: result: o +configure:2770: checking whether we are using the GNU C compiler +configure:2789: clang -c conftest.c >&5 +configure:2789: $? = 0 +configure:2798: result: yes +configure:2807: checking whether clang accepts -g +configure:2827: clang -c -g conftest.c >&5 +configure:2827: $? = 0 +configure:2868: result: yes +configure:2885: checking for clang option to accept ISO C89 +configure:2948: clang -c -g -O2 conftest.c >&5 +configure:2948: $? = 0 +configure:2961: result: none needed +configure:3024: checking for a BSD-compatible install +configure:3092: result: /usr/bin/install -c +configure:3146: checking for ranlib +configure:3162: found /usr/bin/ranlib +configure:3173: result: ranlib +configure:3195: checking for a sed that does not truncate output +configure:3259: result: /bin/sed +configure:3264: checking for a thread-safe mkdir -p +configure:3303: result: /bin/mkdir -p +configure:3323: checking build system type +configure:3337: result: x86_64-unknown-linux-gnu +configure:3357: checking host system type +configure:3370: result: x86_64-unknown-linux-gnu +configure:3438: checking for pthread_create in -lpthread +configure:3463: clang -o conftest -g -O3 conftest.c -lpthread -lkqueue >&5 +configure:3463: $? = 0 +configure:3472: result: yes +configure:3483: checking for MD5_Update in -lcrypto +configure:3508: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:3508: $? = 0 +configure:3517: result: yes +configure:3534: checking how to run the C preprocessor +configure:3565: clang -E conftest.c +configure:3565: $? = 0 +configure:3579: clang -E conftest.c +conftest.c:12:10: fatal error: 'ac_nonexistent.h' file not found +#include + ^ +1 error generated. +configure:3579: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| /* end confdefs.h. */ +| #include +configure:3604: result: clang -E +configure:3624: clang -E conftest.c +configure:3624: $? = 0 +configure:3638: clang -E conftest.c +conftest.c:12:10: fatal error: 'ac_nonexistent.h' file not found +#include + ^ +1 error generated. +configure:3638: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| /* end confdefs.h. */ +| #include +configure:3667: checking for grep that handles long lines and -e +configure:3725: result: /bin/grep +configure:3730: checking for egrep +configure:3792: result: /bin/grep -E +configure:3797: checking for ANSI C header files +configure:3817: clang -c -g -O3 conftest.c >&5 +configure:3817: $? = 0 +configure:3890: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:3890: $? = 0 +configure:3890: ./conftest +configure:3890: $? = 0 +configure:3901: result: yes +configure:3914: checking for sys/types.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for sys/stat.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for stdlib.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for string.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for memory.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for strings.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for inttypes.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for stdint.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3914: checking for unistd.h +configure:3914: clang -c -g -O3 conftest.c >&5 +configure:3914: $? = 0 +configure:3914: result: yes +configure:3929: checking arpa/inet.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking arpa/inet.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for arpa/inet.h +configure:3929: result: yes +configure:3929: checking fcntl.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking fcntl.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for fcntl.h +configure:3929: result: yes +configure:3929: checking for inttypes.h +configure:3929: result: yes +configure:3929: checking limits.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking limits.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for limits.h +configure:3929: result: yes +configure:3929: checking netdb.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking netdb.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for netdb.h +configure:3929: result: yes +configure:3929: checking netinet/in.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking netinet/in.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for netinet/in.h +configure:3929: result: yes +configure:3929: checking stddef.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking stddef.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for stddef.h +configure:3929: result: yes +configure:3929: checking for stdint.h +configure:3929: result: yes +configure:3929: checking for stdlib.h +configure:3929: result: yes +configure:3929: checking for string.h +configure:3929: result: yes +configure:3929: checking sys/ioctl.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking sys/ioctl.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for sys/ioctl.h +configure:3929: result: yes +configure:3929: checking sys/param.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking sys/param.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for sys/param.h +configure:3929: result: yes +configure:3929: checking sys/socket.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking sys/socket.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for sys/socket.h +configure:3929: result: yes +configure:3929: checking sys/time.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking sys/time.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for sys/time.h +configure:3929: result: yes +configure:3929: checking syslog.h usability +configure:3929: clang -c -g -O3 conftest.c >&5 +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking syslog.h presence +configure:3929: clang -E conftest.c +configure:3929: $? = 0 +configure:3929: result: yes +configure:3929: checking for syslog.h +configure:3929: result: yes +configure:3929: checking for unistd.h +configure:3929: result: yes +configure:3941: checking for inline +configure:3957: clang -c -g -O3 conftest.c >&5 +configure:3957: $? = 0 +configure:3965: result: inline +configure:3983: checking for int32_t +configure:3983: clang -c -g -O3 conftest.c >&5 +configure:3983: $? = 0 +configure:3983: clang -c -g -O3 conftest.c >&5 +conftest.c:75:24: error: 'test_array' declared as an array with a negative size +static int test_array [1 - 2 * !((int32_t) (((((int32_t) 1 << N) << N) - 1) * 2 + 1) + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 error generated. +configure:3983: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| enum { N = 32 / 2 - 1 }; +| int +| main () +| { +| static int test_array [1 - 2 * !((int32_t) (((((int32_t) 1 << N) << N) - 1) * 2 + 1) +| < (int32_t) (((((int32_t) 1 << N) << N) - 1) * 2 + 2))]; +| test_array [0] = 0; +| return test_array [0]; +| +| ; +| return 0; +| } +configure:3983: result: yes +configure:3994: checking for int64_t +configure:3994: clang -c -g -O3 conftest.c >&5 +configure:3994: $? = 0 +configure:3994: clang -c -g -O3 conftest.c >&5 +conftest.c:75:24: error: 'test_array' declared as an array with a negative size +static int test_array [1 - 2 * !((int64_t) (((((int64_t) 1 << N) << N) - 1) * 2 + 1) + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 error generated. +configure:3994: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| enum { N = 64 / 2 - 1 }; +| int +| main () +| { +| static int test_array [1 - 2 * !((int64_t) (((((int64_t) 1 << N) << N) - 1) * 2 + 1) +| < (int64_t) (((((int64_t) 1 << N) << N) - 1) * 2 + 2))]; +| test_array [0] = 0; +| return test_array [0]; +| +| ; +| return 0; +| } +configure:3994: result: yes +configure:4005: checking for off_t +configure:4005: clang -c -g -O3 conftest.c >&5 +configure:4005: $? = 0 +configure:4005: clang -c -g -O3 conftest.c >&5 +conftest.c:74:20: error: expected expression +if (sizeof ((off_t))) + ^ +1 error generated. +configure:4005: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| int +| main () +| { +| if (sizeof ((off_t))) +| return 0; +| ; +| return 0; +| } +configure:4005: result: yes +configure:4016: checking for pid_t +configure:4016: clang -c -g -O3 conftest.c >&5 +configure:4016: $? = 0 +configure:4016: clang -c -g -O3 conftest.c >&5 +conftest.c:74:20: error: expected expression +if (sizeof ((pid_t))) + ^ +1 error generated. +configure:4016: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| int +| main () +| { +| if (sizeof ((pid_t))) +| return 0; +| ; +| return 0; +| } +configure:4016: result: yes +configure:4027: checking for size_t +configure:4027: clang -c -g -O3 conftest.c >&5 +configure:4027: $? = 0 +configure:4027: clang -c -g -O3 conftest.c >&5 +conftest.c:74:21: error: expected expression +if (sizeof ((size_t))) + ^ +1 error generated. +configure:4027: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| int +| main () +| { +| if (sizeof ((size_t))) +| return 0; +| ; +| return 0; +| } +configure:4027: result: yes +configure:4038: checking for ssize_t +configure:4038: clang -c -g -O3 conftest.c >&5 +configure:4038: $? = 0 +configure:4038: clang -c -g -O3 conftest.c >&5 +conftest.c:74:22: error: expected expression +if (sizeof ((ssize_t))) + ^ +1 error generated. +configure:4038: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| int +| main () +| { +| if (sizeof ((ssize_t))) +| return 0; +| ; +| return 0; +| } +configure:4038: result: yes +configure:4049: checking for struct stat.st_blocks +configure:4049: clang -c -g -O3 conftest.c >&5 +configure:4049: $? = 0 +configure:4049: result: yes +configure:4069: checking for uint16_t +configure:4069: clang -c -g -O3 conftest.c >&5 +configure:4069: $? = 0 +configure:4069: result: yes +configure:4081: checking for uint32_t +configure:4081: clang -c -g -O3 conftest.c >&5 +configure:4081: $? = 0 +configure:4081: result: yes +configure:4095: checking for uint64_t +configure:4095: clang -c -g -O3 conftest.c >&5 +configure:4095: $? = 0 +configure:4095: result: yes +configure:4109: checking for uint8_t +configure:4109: clang -c -g -O3 conftest.c >&5 +configure:4109: $? = 0 +configure:4109: result: yes +configure:4125: checking whether lstat correctly handles trailing slash +configure:4151: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4151: $? = 0 +configure:4151: ./conftest +configure:4151: $? = 0 +configure:4168: result: yes +configure:4189: checking for stdlib.h +configure:4189: result: yes +configure:4199: checking for GNU libc compatible malloc +configure:4223: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4223: $? = 0 +configure:4223: ./conftest +configure:4223: $? = 0 +configure:4233: result: yes +configure:4256: checking for stdlib.h +configure:4256: result: yes +configure:4266: checking for GNU libc compatible realloc +configure:4290: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4290: $? = 0 +configure:4290: ./conftest +configure:4290: $? = 0 +configure:4300: result: yes +configure:4324: checking for ftruncate +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for memset +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:69:6: warning: incompatible redeclaration of library function 'memset' [-Wincompatible-library-redeclaration] +char memset (); + ^ +conftest.c:69:6: note: 'memset' is a builtin with type 'void *(void *, int, unsigned long)' +1 warning generated. +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for realpath +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for socket +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strcasecmp +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:72:6: warning: incompatible redeclaration of library function 'strcasecmp' [-Wincompatible-library-redeclaration] +char strcasecmp (); + ^ +conftest.c:72:6: note: 'strcasecmp' is a builtin with type 'int (const char *, const char *)' +1 warning generated. +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strchr +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:73:6: warning: incompatible redeclaration of library function 'strchr' [-Wincompatible-library-redeclaration] +char strchr (); + ^ +conftest.c:73:6: note: 'strchr' is a builtin with type 'char *(const char *, int)' +1 warning generated. +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strncasecmp +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:74:6: warning: incompatible redeclaration of library function 'strncasecmp' [-Wincompatible-library-redeclaration] +char strncasecmp (); + ^ +conftest.c:74:6: note: 'strncasecmp' is a builtin with type 'int (const char *, const char *, unsigned long)' +1 warning generated. +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strspn +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:75:6: warning: incompatible redeclaration of library function 'strspn' [-Wincompatible-library-redeclaration] +char strspn (); + ^ +conftest.c:75:6: note: 'strspn' is a builtin with type 'unsigned long (const char *, const char *)' +1 warning generated. +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strtol +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4324: $? = 0 +configure:4324: result: yes +configure:4324: checking for strtoull +configure:4324: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4324: $? = 0 +configure:4324: result: yes +configure:4342: checking for special C compiler options needed for large files +configure:4387: result: no +configure:4393: checking for _FILE_OFFSET_BITS value needed for large files +configure:4418: clang -c -g -O3 conftest.c >&5 +configure:4418: $? = 0 +configure:4450: result: no +configure:4538: checking aio.h usability +configure:4538: clang -c -g -O3 conftest.c >&5 +configure:4538: $? = 0 +configure:4538: result: yes +configure:4538: checking aio.h presence +configure:4538: clang -E conftest.c +configure:4538: $? = 0 +configure:4538: result: yes +configure:4538: checking for aio.h +configure:4538: result: yes +configure:4538: checking sched.h usability +configure:4538: clang -c -g -O3 conftest.c >&5 +configure:4538: $? = 0 +configure:4538: result: yes +configure:4538: checking sched.h presence +configure:4538: clang -E conftest.c +configure:4538: $? = 0 +configure:4538: result: yes +configure:4538: checking for sched.h +configure:4538: result: yes +configure:4538: checking uuid.h usability +configure:4538: clang -c -g -O3 conftest.c >&5 +conftest.c:90:10: fatal error: 'uuid.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| #include +configure:4538: result: no +configure:4538: checking uuid.h presence +configure:4538: clang -E conftest.c +conftest.c:57:10: fatal error: 'uuid.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +configure:4538: result: no +configure:4538: checking for uuid.h +configure:4538: result: no +configure:4538: checking sys/disk.h usability +configure:4538: clang -c -g -O3 conftest.c >&5 +conftest.c:90:10: fatal error: 'sys/disk.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| #include +configure:4538: result: no +configure:4538: checking sys/disk.h presence +configure:4538: clang -E conftest.c +conftest.c:57:10: fatal error: 'sys/disk.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +configure:4538: result: no +configure:4538: checking for sys/disk.h +configure:4538: result: no +configure:4538: checking sys/disklabel.h usability +configure:4538: clang -c -g -O3 conftest.c >&5 +conftest.c:90:10: fatal error: 'sys/disklabel.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| #include +configure:4538: result: no +configure:4538: checking sys/disklabel.h presence +configure:4538: clang -E conftest.c +conftest.c:57:10: fatal error: 'sys/disklabel.h' file not found +#include + ^ +1 error generated. +configure:4538: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| /* end confdefs.h. */ +| #include +configure:4538: result: no +configure:4538: checking for sys/disklabel.h +configure:4538: result: no +configure:4550: checking pthread.h usability +configure:4550: clang -c -g -O3 conftest.c >&5 +configure:4550: $? = 0 +configure:4550: result: yes +configure:4550: checking pthread.h presence +configure:4550: clang -E conftest.c +configure:4550: $? = 0 +configure:4550: result: yes +configure:4550: checking for pthread.h +configure:4550: result: yes +configure:4562: checking for pthread_np.h +configure:4562: clang -c -g -O3 conftest.c >&5 +conftest.c:63:10: fatal error: 'pthread_np.h' file not found +#include + ^ +1 error generated. +configure:4562: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| /* end confdefs.h. */ +| #if HAVE_PTHREAD_H +| #include +| #endif +| +| +| #include +configure:4562: result: no +configure:4579: checking for strlcpy +configure:4579: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +/tmp/conftest-be4176.o: In function `main': +/home/payes/istgt/conftest.c:92: undefined reference to `strlcpy' +clang: error: linker command failed with exit code 1 (use -v to see invocation) +configure:4579: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| /* end confdefs.h. */ +| /* Define strlcpy to an innocuous variant, in case declares strlcpy. +| For example, HP-UX 11i declares gettimeofday. */ +| #define strlcpy innocuous_strlcpy +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char strlcpy (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef strlcpy +| +| /* Override any GCC internal prototype to avoid an error. +| Use char because int might match the return type of a GCC +| builtin and then its argument prototype would still apply. */ +| #ifdef __cplusplus +| extern "C" +| #endif +| char strlcpy (); +| /* The GNU C library defines this for functions which it implements +| to always fail with ENOSYS. Some functions are actually named +| something starting with __ and the normal name is an alias. */ +| #if defined __stub_strlcpy || defined __stub___strlcpy +| choke me +| #endif +| +| int +| main () +| { +| return strlcpy (); +| ; +| return 0; +| } +configure:4579: result: no +configure:4579: checking for arc4random +configure:4579: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +/tmp/conftest-e7aca1.o: In function `main': +/home/payes/istgt/conftest.c:92: undefined reference to `arc4random' +clang: error: linker command failed with exit code 1 (use -v to see invocation) +configure:4579: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| /* end confdefs.h. */ +| /* Define arc4random to an innocuous variant, in case declares arc4random. +| For example, HP-UX 11i declares gettimeofday. */ +| #define arc4random innocuous_arc4random +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char arc4random (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef arc4random +| +| /* Override any GCC internal prototype to avoid an error. +| Use char because int might match the return type of a GCC +| builtin and then its argument prototype would still apply. */ +| #ifdef __cplusplus +| extern "C" +| #endif +| char arc4random (); +| /* The GNU C library defines this for functions which it implements +| to always fail with ENOSYS. Some functions are actually named +| something starting with __ and the normal name is an alias. */ +| #if defined __stub_arc4random || defined __stub___arc4random +| choke me +| #endif +| +| int +| main () +| { +| return arc4random (); +| ; +| return 0; +| } +configure:4579: result: no +configure:4579: checking for srandomdev +configure:4579: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +/tmp/conftest-66865d.o: In function `main': +/home/payes/istgt/conftest.c:92: undefined reference to `srandomdev' +clang: error: linker command failed with exit code 1 (use -v to see invocation) +configure:4579: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| /* end confdefs.h. */ +| /* Define srandomdev to an innocuous variant, in case declares srandomdev. +| For example, HP-UX 11i declares gettimeofday. */ +| #define srandomdev innocuous_srandomdev +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char srandomdev (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef srandomdev +| +| /* Override any GCC internal prototype to avoid an error. +| Use char because int might match the return type of a GCC +| builtin and then its argument prototype would still apply. */ +| #ifdef __cplusplus +| extern "C" +| #endif +| char srandomdev (); +| /* The GNU C library defines this for functions which it implements +| to always fail with ENOSYS. Some functions are actually named +| something starting with __ and the normal name is an alias. */ +| #if defined __stub_srandomdev || defined __stub___srandomdev +| choke me +| #endif +| +| int +| main () +| { +| return srandomdev (); +| ; +| return 0; +| } +configure:4579: result: no +configure:4579: checking for pthread_yield +configure:4579: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4579: $? = 0 +configure:4579: result: yes +configure:4579: checking for sched_yield +configure:4579: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:4579: $? = 0 +configure:4579: result: yes +configure:4591: checking for pthread_set_name_np +configure:4591: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +/tmp/conftest-b3b81b.o: In function `main': +/home/payes/istgt/conftest.c:94: undefined reference to `pthread_set_name_np' +clang: error: linker command failed with exit code 1 (use -v to see invocation) +configure:4591: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| /* end confdefs.h. */ +| /* Define pthread_set_name_np to an innocuous variant, in case declares pthread_set_name_np. +| For example, HP-UX 11i declares gettimeofday. */ +| #define pthread_set_name_np innocuous_pthread_set_name_np +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char pthread_set_name_np (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef pthread_set_name_np +| +| /* Override any GCC internal prototype to avoid an error. +| Use char because int might match the return type of a GCC +| builtin and then its argument prototype would still apply. */ +| #ifdef __cplusplus +| extern "C" +| #endif +| char pthread_set_name_np (); +| /* The GNU C library defines this for functions which it implements +| to always fail with ENOSYS. Some functions are actually named +| something starting with __ and the normal name is an alias. */ +| #if defined __stub_pthread_set_name_np || defined __stub___pthread_set_name_np +| choke me +| #endif +| +| int +| main () +| { +| return pthread_set_name_np (); +| ; +| return 0; +| } +configure:4591: result: no +configure:4591: checking for setproctitle +configure:4591: clang -o conftest -g -O3 conftest.c -lcrypto -lpthread -lkqueue >&5 +/tmp/conftest-494a7f.o: In function `main': +/home/payes/istgt/conftest.c:94: undefined reference to `setproctitle' +clang: error: linker command failed with exit code 1 (use -v to see invocation) +configure:4591: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| /* end confdefs.h. */ +| /* Define setproctitle to an innocuous variant, in case declares setproctitle. +| For example, HP-UX 11i declares gettimeofday. */ +| #define setproctitle innocuous_setproctitle +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char setproctitle (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef setproctitle +| +| /* Override any GCC internal prototype to avoid an error. +| Use char because int might match the return type of a GCC +| builtin and then its argument prototype would still apply. */ +| #ifdef __cplusplus +| extern "C" +| #endif +| char setproctitle (); +| /* The GNU C library defines this for functions which it implements +| to always fail with ENOSYS. Some functions are actually named +| something starting with __ and the normal name is an alias. */ +| #if defined __stub_setproctitle || defined __stub___setproctitle +| choke me +| #endif +| +| int +| main () +| { +| return setproctitle (); +| ; +| return 0; +| } +configure:4591: result: no +configure:4603: checking for mkdep +configure:4636: result: no +configure:4695: checking whether the C compiler accepts -Wall +configure:4709: clang -c -g -O3 -Wall conftest.c >&5 +configure:4709: $? = 0 +configure:4710: result: yes +configure:4721: checking whether the C compiler accepts -Wextra +configure:4735: clang -c -g -O3 -Wall -Wextra conftest.c >&5 +configure:4735: $? = 0 +configure:4736: result: yes +configure:4746: checking whether to use debug mode +configure:4755: result: no +configure:4761: checking whether to use symlink device +configure:4770: result: no +configure:4776: checking which syslog facility to use +configure:4797: result: "local7" +configure:4800: checking which syslog priority to use +configure:4821: result: "info" +configure:4841: checking VirtualBox Virtual Disk support +configure:4861: result: no +configure:4920: checking for PTHREAD_MUTEX_ADAPTIVE_NP +configure:4937: clang -c -g -O3 -Wall -Wextra conftest.c >&5 +configure:4937: $? = 0 +configure:4938: result: yes +configure:4952: checking for sys/types.h +configure:4952: result: yes +configure:4964: checking for machine/atomic.h +configure:4964: clang -c -g -O3 -Wall -Wextra conftest.c >&5 +conftest.c:69:10: fatal error: 'machine/atomic.h' file not found +#include + ^ +1 error generated. +configure:4964: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| #if HAVE_SYS_TYPES_H +| #include +| #endif +| +| +| #include +configure:4964: result: no +configure:4980: checking sys/atomic.h usability +configure:4980: clang -c -g -O3 -Wall -Wextra conftest.c >&5 +conftest.c:97:10: fatal error: 'sys/atomic.h' file not found +#include + ^ +1 error generated. +configure:4980: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| #include +configure:4980: result: no +configure:4980: checking sys/atomic.h presence +configure:4980: clang -E conftest.c +conftest.c:64:10: fatal error: 'sys/atomic.h' file not found +#include + ^ +1 error generated. +configure:4980: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| #include +configure:4980: result: no +configure:4980: checking for sys/atomic.h +configure:4980: result: no +configure:5000: checking for atomic operations +configure:5022: clang -o conftest -g -O3 -Wall -Wextra conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:68:10: fatal error: 'machine/atomic.h' file not found +#include + ^ +1 error generated. +configure:5022: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| +| #if HAVE_SYS_TYPES_H +| #include +| #endif +| #include +| +| int +| main () +| { +| +| int x, y; +| atomic_store_rel_int(&x, 1); +| y = atomic_load_acq_int(&x); +| +| ; +| return 0; +| } +configure:5058: clang -o conftest -g -O3 -Wall -Wextra conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:68:10: fatal error: 'sys/atomic.h' file not found +#include + ^ +1 error generated. +configure:5058: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| +| #if HAVE_SYS_TYPES_H +| #include +| #endif +| #include +| +| int +| main () +| { +| +| unsigned int x, y; +| atomic_swap_uint(&x, 1); +| y = atomic_or_uint_nv(&x, 0); +| +| ; +| return 0; +| } +configure:5092: clang -o conftest -g -O3 -Wall -Wextra conftest.c -lcrypto -lpthread -lkqueue >&5 +conftest.c:68:10: fatal error: 'sys/atomic.h' file not found +#include + ^ +1 error generated. +configure:5092: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "istgt" +| #define PACKAGE_TARNAME "istgt" +| #define PACKAGE_VERSION "0.5" +| #define PACKAGE_STRING "istgt 0.5" +| #define PACKAGE_BUGREPORT "" +| #define PACKAGE_URL "" +| #define _GNU_SOURCE 1 +| #define HAVE_LIBPTHREAD 1 +| #define HAVE_LIBCRYPTO 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_ARPA_INET_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_NETDB_H 1 +| #define HAVE_NETINET_IN_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_SOCKET_H 1 +| #define HAVE_SYS_TIME_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_MALLOC 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_REALLOC 1 +| #define HAVE_FTRUNCATE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_SOCKET 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRNCASECMP 1 +| #define HAVE_STRSPN 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOULL 1 +| #define HAVE_AIO_H 1 +| #define HAVE_SCHED_H 1 +| #define HAVE_PTHREAD_H 1 +| #define HAVE_PTHREAD_YIELD 1 +| #define HAVE_SCHED_YIELD 1 +| #define DEFAULT_LOG_FACILITY "local7" +| #define DEFAULT_LOG_PRIORITY "info" +| #define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +| #define HAVE_SYS_TYPES_H 1 +| /* end confdefs.h. */ +| +| #if HAVE_SYS_TYPES_H +| #include +| #endif +| #include +| +| int +| main () +| { +| +| membar_producer(); +| +| ; +| return 0; +| } +configure:5100: result: no +configure:5108: checking for gcc builtin atomic operations +configure:5129: clang -o conftest -g -O3 -Wall -Wextra conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:5129: $? = 0 +configure:5161: clang -o conftest -g -O3 -Wall -Wextra conftest.c -lcrypto -lpthread -lkqueue >&5 +configure:5161: $? = 0 +configure:5169: result: yes +configure:5290: creating ./config.status + +## ---------------------- ## +## Running config.status. ## +## ---------------------- ## + +This file was extended by istgt config.status 0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = + CONFIG_HEADERS = + CONFIG_LINKS = + CONFIG_COMMANDS = + $ ./config.status + +on dev + +config.status:874: creating Makefile +config.status:874: creating src/Makefile +config.status:874: creating etc/Makefile +config.status:874: creating doc/Makefile +config.status:874: creating src/build.h +config.status:874: creating src/config.h +config.status:1055: src/config.h is unchanged + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_build=x86_64-unknown-linux-gnu +ac_cv_c_compiler_gnu=yes +ac_cv_c_inline=inline +ac_cv_c_int32_t=yes +ac_cv_c_int64_t=yes +ac_cv_c_uint16_t=yes +ac_cv_c_uint32_t=yes +ac_cv_c_uint64_t=yes +ac_cv_c_uint8_t=yes +ac_cv_env_CC_set= +ac_cv_env_CC_value= +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_LIBS_set= +ac_cv_env_LIBS_value= +ac_cv_env_SUBPROGRAM_set= +ac_cv_env_SUBPROGRAM_value= +ac_cv_env_build_alias_set= +ac_cv_env_build_alias_value= +ac_cv_env_host_alias_set= +ac_cv_env_host_alias_value= +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_func_arc4random=no +ac_cv_func_ftruncate=yes +ac_cv_func_lstat_dereferences_slashed_symlink=yes +ac_cv_func_malloc_0_nonnull=yes +ac_cv_func_memset=yes +ac_cv_func_pthread_set_name_np=no +ac_cv_func_pthread_yield=yes +ac_cv_func_realloc_0_nonnull=yes +ac_cv_func_realpath=yes +ac_cv_func_sched_yield=yes +ac_cv_func_setproctitle=no +ac_cv_func_socket=yes +ac_cv_func_srandomdev=no +ac_cv_func_strcasecmp=yes +ac_cv_func_strchr=yes +ac_cv_func_strlcpy=no +ac_cv_func_strncasecmp=yes +ac_cv_func_strspn=yes +ac_cv_func_strtol=yes +ac_cv_func_strtoull=yes +ac_cv_header_aio_h=yes +ac_cv_header_arpa_inet_h=yes +ac_cv_header_fcntl_h=yes +ac_cv_header_inttypes_h=yes +ac_cv_header_limits_h=yes +ac_cv_header_machine_atomic_h=no +ac_cv_header_memory_h=yes +ac_cv_header_netdb_h=yes +ac_cv_header_netinet_in_h=yes +ac_cv_header_pthread_h=yes +ac_cv_header_pthread_np_h=no +ac_cv_header_sched_h=yes +ac_cv_header_stdc=yes +ac_cv_header_stddef_h=yes +ac_cv_header_stdint_h=yes +ac_cv_header_stdlib_h=yes +ac_cv_header_string_h=yes +ac_cv_header_strings_h=yes +ac_cv_header_sys_atomic_h=no +ac_cv_header_sys_disk_h=no +ac_cv_header_sys_disklabel_h=no +ac_cv_header_sys_ioctl_h=yes +ac_cv_header_sys_param_h=yes +ac_cv_header_sys_socket_h=yes +ac_cv_header_sys_stat_h=yes +ac_cv_header_sys_time_h=yes +ac_cv_header_sys_types_h=yes +ac_cv_header_syslog_h=yes +ac_cv_header_unistd_h=yes +ac_cv_header_uuid_h=no +ac_cv_host=x86_64-unknown-linux-gnu +ac_cv_lib_crypto_MD5_Update=yes +ac_cv_lib_pthread_pthread_create=yes +ac_cv_member_struct_stat_st_blocks=yes +ac_cv_objext=o +ac_cv_path_EGREP='/bin/grep -E' +ac_cv_path_GREP=/bin/grep +ac_cv_path_SED=/bin/sed +ac_cv_path_install='/usr/bin/install -c' +ac_cv_path_mkdir=/bin/mkdir +ac_cv_prog_CPP='clang -E' +ac_cv_prog_ac_ct_CC=clang +ac_cv_prog_ac_ct_RANLIB=ranlib +ac_cv_prog_cc_c89= +ac_cv_prog_cc_g=yes +ac_cv_sys_file_offset_bits=no +ac_cv_sys_largefile_CC=no +ac_cv_type_off_t=yes +ac_cv_type_pid_t=yes +ac_cv_type_size_t=yes +ac_cv_type_ssize_t=yes + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +ALLOW_SYMLINK_DEVICE='' +CC='clang' +CFLAGS='-g -O3 -Wall -Wextra' +CPP='clang -E' +CPPFLAGS='' +DEBUG='' +DEFS='-DHAVE_CONFIG_H' +ECHO_C='' +ECHO_N='-n' +ECHO_T='' +EGREP='/bin/grep -E' +EXEEXT='' +GREP='/bin/grep' +INSTALL_DATA='${INSTALL} -m 644' +INSTALL_PROGRAM='${INSTALL}' +INSTALL_SCRIPT='${INSTALL}' +LDFLAGS='' +LIBOBJS='' +LIBS='-lcrypto -lpthread -lkqueue ' +LTLIBOBJS='' +MKDEP='' +MKDIR_P='/bin/mkdir -p' +OBJEXT='o' +PACKAGE_BUGREPORT='' +PACKAGE_NAME='istgt' +PACKAGE_STRING='istgt 0.5' +PACKAGE_TARNAME='istgt' +PACKAGE_URL='' +PACKAGE_VERSION='0.5' +PATH_SEPARATOR=':' +RANLIB='ranlib' +SED='/bin/sed' +SHELL='/bin/bash' +SUBPROGRAM='' +ac_ct_CC='clang' +bindir='${exec_prefix}/bin' +build='x86_64-unknown-linux-gnu' +build_alias='' +build_cpu='x86_64' +build_os='linux-gnu' +build_vendor='unknown' +configdir='/usr/local/etc/istgt' +datadir='${datarootdir}' +datarootdir='${prefix}/share' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +dvidir='${docdir}' +exec_prefix='${prefix}' +host='x86_64-unknown-linux-gnu' +host_alias='' +host_cpu='x86_64' +host_os='linux-gnu' +host_vendor='unknown' +htmldir='${docdir}' +includedir='${prefix}/include' +infodir='${datarootdir}/info' +libdir='${exec_prefix}/lib' +libexecdir='${exec_prefix}/libexec' +localedir='${datarootdir}/locale' +localstatedir='${prefix}/var' +mandir='${datarootdir}/man' +mediadir='/var/istgt' +oldincludedir='/usr/include' +pdfdir='${docdir}' +prefix='/usr/local' +program_transform_name='s,x,x,' +psdir='${docdir}' +rcdir='/etc/init.d' +rctemplate='istgt_linux.sh.in' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sysconfdir='${prefix}/etc' +target_alias='' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +/* confdefs.h */ +#define PACKAGE_NAME "istgt" +#define PACKAGE_TARNAME "istgt" +#define PACKAGE_VERSION "0.5" +#define PACKAGE_STRING "istgt 0.5" +#define PACKAGE_BUGREPORT "" +#define PACKAGE_URL "" +#define _GNU_SOURCE 1 +#define HAVE_LIBPTHREAD 1 +#define HAVE_LIBCRYPTO 1 +#define STDC_HEADERS 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_ARPA_INET_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_NETDB_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_STDDEF_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYSLOG_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +#define HAVE_ST_BLOCKS 1 +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +#define HAVE_STDLIB_H 1 +#define HAVE_MALLOC 1 +#define HAVE_STDLIB_H 1 +#define HAVE_REALLOC 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_MEMSET 1 +#define HAVE_REALPATH 1 +#define HAVE_SOCKET 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRCHR 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_STRSPN 1 +#define HAVE_STRTOL 1 +#define HAVE_STRTOULL 1 +#define HAVE_AIO_H 1 +#define HAVE_SCHED_H 1 +#define HAVE_PTHREAD_H 1 +#define HAVE_PTHREAD_YIELD 1 +#define HAVE_SCHED_YIELD 1 +#define DEFAULT_LOG_FACILITY "local7" +#define DEFAULT_LOG_PRIORITY "info" +#define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 +#define HAVE_SYS_TYPES_H 1 +#define USE_GCC_ATOMIC 1 +#define HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT 1 +#define HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT 1 +#define HAVE_GCC_ATOMIC_SYNCHRONIZE 1 + +configure: exit 0 diff --git a/config.status b/config.status new file mode 100755 index 00000000..006bb19c --- /dev/null +++ b/config.status @@ -0,0 +1,1075 @@ +#! /bin/bash +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/bash} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by istgt $as_me 0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" Makefile src/Makefile etc/Makefile doc/Makefile src/build.h" +config_headers=" src/config.h" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +ac_cs_config="" +ac_cs_version="\ +istgt config.status 0.5 +configured by ./configure, generated by GNU Autoconf 2.69, + with options \"$ac_cs_config\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/home/payes/istgt' +srcdir='.' +INSTALL='/usr/bin/install -c' +MKDIR_P='/bin/mkdir -p' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X /bin/bash './configure' $ac_configure_extra_args --no-create --no-recursion + shift + $as_echo "running CONFIG_SHELL=/bin/bash $*" >&6 + CONFIG_SHELL='/bin/bash' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "src/build.h") CONFIG_FILES="$CONFIG_FILES src/build.h" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && +S["LTLIBOBJS"]="" +S["ALLOW_SYMLINK_DEVICE"]="" +S["DEBUG"]="" +S["mediadir"]="/var/istgt" +S["configdir"]="/usr/local/etc/istgt" +S["MKDEP"]="" +S["LIBOBJS"]="" +S["EGREP"]="/bin/grep -E" +S["GREP"]="/bin/grep" +S["CPP"]="clang -E" +S["host_os"]="linux-gnu" +S["host_vendor"]="unknown" +S["host_cpu"]="x86_64" +S["host"]="x86_64-unknown-linux-gnu" +S["build_os"]="linux-gnu" +S["build_vendor"]="unknown" +S["build_cpu"]="x86_64" +S["build"]="x86_64-unknown-linux-gnu" +S["rcdir"]="/etc/init.d" +S["rctemplate"]="istgt_linux.sh.in" +S["MKDIR_P"]="/bin/mkdir -p" +S["SED"]="/bin/sed" +S["RANLIB"]="ranlib" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="clang" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-g -O3 -Wall -Wextra" +S["CC"]="clang" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="-lcrypto -lpthread -lkqueue " +S["SUBPROGRAM"]="" +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DHAVE_CONFIG_H" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="" +S["PACKAGE_STRING"]="istgt 0.5" +S["PACKAGE_VERSION"]="0.5" +S["PACKAGE_TARNAME"]="istgt" +S["PACKAGE_NAME"]="istgt" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/bash" +_ACAWK +cat >>"$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +D["PACKAGE_NAME"]=" \"istgt\"" +D["PACKAGE_TARNAME"]=" \"istgt\"" +D["PACKAGE_VERSION"]=" \"0.5\"" +D["PACKAGE_STRING"]=" \"istgt 0.5\"" +D["PACKAGE_BUGREPORT"]=" \"\"" +D["PACKAGE_URL"]=" \"\"" +D["_GNU_SOURCE"]=" 1" +D["HAVE_LIBPTHREAD"]=" 1" +D["HAVE_LIBCRYPTO"]=" 1" +D["STDC_HEADERS"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_MEMORY_H"]=" 1" +D["HAVE_STRINGS_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_ARPA_INET_H"]=" 1" +D["HAVE_FCNTL_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_LIMITS_H"]=" 1" +D["HAVE_NETDB_H"]=" 1" +D["HAVE_NETINET_IN_H"]=" 1" +D["HAVE_STDDEF_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_SYS_IOCTL_H"]=" 1" +D["HAVE_SYS_PARAM_H"]=" 1" +D["HAVE_SYS_SOCKET_H"]=" 1" +D["HAVE_SYS_TIME_H"]=" 1" +D["HAVE_SYSLOG_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_STRUCT_STAT_ST_BLOCKS"]=" 1" +D["HAVE_ST_BLOCKS"]=" 1" +D["LSTAT_FOLLOWS_SLASHED_SYMLINK"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_MALLOC"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_REALLOC"]=" 1" +D["HAVE_FTRUNCATE"]=" 1" +D["HAVE_MEMSET"]=" 1" +D["HAVE_REALPATH"]=" 1" +D["HAVE_SOCKET"]=" 1" +D["HAVE_STRCASECMP"]=" 1" +D["HAVE_STRCHR"]=" 1" +D["HAVE_STRNCASECMP"]=" 1" +D["HAVE_STRSPN"]=" 1" +D["HAVE_STRTOL"]=" 1" +D["HAVE_STRTOULL"]=" 1" +D["HAVE_AIO_H"]=" 1" +D["HAVE_SCHED_H"]=" 1" +D["HAVE_PTHREAD_H"]=" 1" +D["HAVE_PTHREAD_YIELD"]=" 1" +D["HAVE_SCHED_YIELD"]=" 1" +D["DEFAULT_LOG_FACILITY"]=" \"local7\"" +D["DEFAULT_LOG_PRIORITY"]=" \"info\"" +D["HAVE_PTHREAD_MUTEX_ADAPTIVE_NP"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["USE_GCC_ATOMIC"]=" 1" +D["HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT"]=" 1" +D["HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT"]=" 1" +D["HAVE_GCC_ATOMIC_SYNCHRONIZE"]=" 1" + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { + line = $ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 diff --git a/config.sub b/config.sub new file mode 100755 index 00000000..9d7f7339 --- /dev/null +++ b/config.sub @@ -0,0 +1,1504 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2003-07-04' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 00000000..9243eb5f --- /dev/null +++ b/configure @@ -0,0 +1,6464 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for istgt 0.5. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + +args=$@ + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='istgt' +PACKAGE_TARNAME='istgt' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='istgt 0.5' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="src/istgt.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +ALLOW_SYMLINK_DEVICE +DEBUG +mediadir +configdir +MKDEP +LIBOBJS +EGREP +GREP +CPP +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +rcdir +rctemplate +MKDIR_P +SED +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +SUBPROGRAM +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_largefile +with_configdir +with_mediadir +with_rcdir +enable_debug +enable_symlink_device +with_logfacility +with_logpriority +with_vbox +with_vboxlib +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +SUBPROGRAM +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + + + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures istgt 0.5 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/istgt] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of istgt 0.5:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files + --enable-debug enable debug(logging) + --enable-symlink-device allow symlink device + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-configdir=DIR (default PREFIX/etc/istgt) + --with-mediadir=DIR (default /var/istgt) + --with-rcdir=DIR (default PREFIX/etc/rc.d) + --with-logfacility syslog facility to log with (default "local7") + --with-logpriority syslog priority to log with (default "info") + --with-vbox=INC VirtualBox include + --with-vboxlib=LIB VirtualBox lib + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +istgt configure 0.5 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_find_intX_t LINENO BITS VAR +# ----------------------------------- +# Finds a signed integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_intX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 +$as_echo_n "checking for int$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in int$2_t 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + case $ac_type in #( + int$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_intX_t + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_uintX_t + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by istgt $as_me 0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers src/config.h" + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in clang gcc cc + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in clang gcc cc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + + +# clagn with -O3 +if test "$CC" = "clang" && test "$ac_test_CFLAGS" != "set"; then + CFLAGS="-g -O3" +fi + +# host OS related +vboxinc="/usr/local/src/virtualbox/*/include" +vboxlib="/usr/local/lib/virtualbox" +rctemplate="" + +rcdir='${prefix}/etc/rc.d' + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +case "$host_os" in +*linux*) + LIBS="-lkqueue $LIBS" + tmp="/usr/src/virtualbox/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + fi + vboxlib="/usr/lib/virtualbox" + rctemplate="istgt_linux.sh.in" + + rcdir='/etc/init.d' + + +$as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + ;; +*netbsd*) + SUBPROGRAM="istgt" + rctemplate="istgt_netbsd.sh.in" + + rcdir='/etc/rc.d' + + ;; +*freebsd*) + SUBPROGRAM="istgt" + tmp="/usr/ports/emulators/virtualbox-ose/work/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + else + tmp="/usr/ports/emulators/virtualbox-ose-legacy/work/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + fi + fi + vboxlib="/usr/local/lib/virtualbox" + rctemplate="istgt.sh.in" + + rcdir='${prefix}/etc/rc.d' + + if test "$mandir" = '${datarootdir}/man'; then + mandir='${prefix}/man' + + fi + ;; +esac + +# Checks for libraries. + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MD5_Update in -lcrypto" >&5 +$as_echo_n "checking for MD5_Update in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_MD5_Update+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char MD5_Update (); +int +main () +{ +return MD5_Update (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_MD5_Update=yes +else + ac_cv_lib_crypto_MD5_Update=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_MD5_Update" >&5 +$as_echo "$ac_cv_lib_crypto_MD5_Update" >&6; } +if test "x$ac_cv_lib_crypto_MD5_Update" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPTO 1 +_ACEOF + + LIBS="-lcrypto $LIBS" + +fi + +# Checks for header files. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in arpa/inet.h fcntl.h inttypes.h limits.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" +case $ac_cv_c_int32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int32_t $ac_cv_c_int32_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" +case $ac_cv_c_int64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int64_t $ac_cv_c_int64_t +_ACEOF +;; +esac + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +if test "x$ac_cv_type_pid_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +_ACEOF + + +$as_echo "#define HAVE_ST_BLOCKS 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" fileblocks.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS fileblocks.$ac_objext" + ;; +esac + +fi + + +ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" +case $ac_cv_c_uint16_t in #( + no|yes) ;; #( + *) + + +cat >>confdefs.h <<_ACEOF +#define uint16_t $ac_cv_c_uint16_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" +case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT32_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" +case $ac_cv_c_uint64_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT64_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint64_t $ac_cv_c_uint64_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + + +# Checks for library functions. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 +$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } +if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f conftest.sym conftest.file +echo >conftest.file +if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then + if test "$cross_compiling" = yes; then : + ac_cv_func_lstat_dereferences_slashed_symlink=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + /* Linux will dereference the symlink and fail, as required by POSIX. + That is better in the sense that it means we will not + have to compile and use the lstat wrapper. */ + return lstat ("conftest.sym/", &sbuf) == 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_lstat_dereferences_slashed_symlink=yes +else + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +else + # If the `ln -s' command failed, then we probably don't even + # have an lstat function. + ac_cv_func_lstat_dereferences_slashed_symlink=no +fi +rm -f conftest.sym conftest.file + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 +$as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } + +test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && + +cat >>confdefs.h <<_ACEOF +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 +_ACEOF + + +if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then + case " $LIBOBJS " in + *" lstat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS lstat.$ac_objext" + ;; +esac + +fi + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if ${ac_cv_func_malloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 +$as_echo_n "checking for GNU libc compatible realloc... " >&6; } +if ${ac_cv_func_realloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_realloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *realloc (); +#endif + +int +main () +{ +return ! realloc (0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_realloc_0_nonnull=yes +else + ac_cv_func_realloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } +if test $ac_cv_func_realloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_REALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_REALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" realloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realloc.$ac_objext" + ;; +esac + + +$as_echo "#define realloc rpl_realloc" >>confdefs.h + +fi + + +for ac_func in ftruncate memset realpath socket strcasecmp strchr strncasecmp strspn strtol strtoull +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# check compatibility +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + +for ac_header in aio.h sched.h uuid.h sys/disk.h sys/disklabel.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in pthread.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PTHREAD_H 1 +_ACEOF + +fi + +done + +for ac_header in pthread_np.h +do : + ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "#if HAVE_PTHREAD_H +#include +#endif + +" +if test "x$ac_cv_header_pthread_np_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PTHREAD_NP_H 1 +_ACEOF + +fi + +done + +for ac_func in strlcpy arc4random srandomdev pthread_yield sched_yield +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in pthread_set_name_np setproctitle +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Extract the first word of ""mkdep"", so it can be a program name with args. +set dummy "mkdep"; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_MKDEP+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MKDEP in + [\\/]* | ?:[\\/]*) + ac_cv_path_MKDEP="$MKDEP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_MKDEP="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +MKDEP=$ac_cv_path_MKDEP +if test -n "$MKDEP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDEP" >&5 +$as_echo "$MKDEP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +#if test -z "$MKDEP"; then +# AC_PATH_PROG([MKDEP], ["makedepend"]) +#fi + +# paths +configdir="$ac_default_prefix/etc/istgt" +mediadir="/var/istgt" +if test "$prefix" != "NONE"; then + configdir="$prefix/etc/istgt" +fi + +# Check whether --with-configdir was given. +if test "${with_configdir+set}" = set; then : + withval=$with_configdir; case $withval in + yes|no) + ;; + *) + configdir="$withval" + ;; + esac +fi + + + +# Check whether --with-mediadir was given. +if test "${with_mediadir+set}" = set; then : + withval=$with_mediadir; case $withval in + yes|no) + ;; + *) + mediadir="$withval" + ;; + esac +fi + + + +# startup script directory + +# Check whether --with-rcdir was given. +if test "${with_rcdir+set}" = set; then : + withval=$with_rcdir; case $withval in + yes|no) + ;; + *) + rcdir="$withval" + ;; + esac +fi + + + +# test for -Wall +saved_CFLAGS="$CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler accepts -Wall" >&5 +$as_echo_n "checking whether the C compiler accepts -Wall... " >&6; } +CFLAGS="$CFLAGS -Wall" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; saved_CFLAGS="$CFLAGS" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$saved_CFLAGS" + +# test for -Wextra +saved_CFLAGS="$CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler accepts -Wextra" >&5 +$as_echo_n "checking whether the C compiler accepts -Wextra... " >&6; } +CFLAGS="$CFLAGS -Wextra" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; saved_CFLAGS="$CFLAGS" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$saved_CFLAGS" + +# check enable features +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use debug mode" >&5 +$as_echo_n "checking whether to use debug mode... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define DEBUG 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use symlink device" >&5 +$as_echo_n "checking whether to use symlink device... " >&6; } +# Check whether --enable-symlink-device was given. +if test "${enable_symlink_device+set}" = set; then : + enableval=$enable_symlink_device; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; +$as_echo "#define ALLOW_SYMLINK_DEVICE 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which syslog facility to use" >&5 +$as_echo_n "checking which syslog facility to use... " >&6; } + +# Check whether --with-logfacility was given. +if test "${with_logfacility+set}" = set; then : + withval=$with_logfacility; case $with_logfacility in + daemon|auth|authpriv|local0|local1|local2|local3|local4|local5|local6|local7) + logfacility=$with_logfacility + ;; + *) as_fn_error $? "\"unsupported facility $with_logfacility\"" "$LINENO" 5 + ;; + esac +else + logfacility="local7" +fi + + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LOG_FACILITY "$logfacility" +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$logfacility\"" >&5 +$as_echo "\"$logfacility\"" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which syslog priority to use" >&5 +$as_echo_n "checking which syslog priority to use... " >&6; } + +# Check whether --with-logpriority was given. +if test "${with_logpriority+set}" = set; then : + withval=$with_logpriority; case $with_logpriority in + emerg|alert|crit|err|warning|notice|info|debug) + logpriority=$with_logpriority + ;; + *) as_fn_error $? "\"unsupported priority $with_logpriority\"" "$LINENO" 5 + ;; + esac +else + logpriority="info" +fi + + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LOG_PRIORITY "$logpriority" +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$logpriority\"" >&5 +$as_echo "\"$logpriority\"" >&6; } + +#AC_MSG_CHECKING([whether to use asynchronous io]) +#AC_ARG_WITH([aio], +# AS_HELP_STRING([--with-aio], [use aio (default "no")]), +# [case $with_aio in +# yes) +# AC_DEFINE([USE_AIO], 1, [use aio]) +# AC_MSG_RESULT(yes) +# ;; +# *) +# AC_MSG_RESULT(no) +# ;; +# esac], +# AC_MSG_RESULT(no)) +#AC_SUBST([USE_AIO]) + +# vbox support +vbox="no" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking VirtualBox Virtual Disk support" >&5 +$as_echo_n "checking VirtualBox Virtual Disk support... " >&6; } + +# Check whether --with-vbox was given. +if test "${with_vbox+set}" = set; then : + withval=$with_vbox; case $with_vbox in + no) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + yes|*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + vbox="yes" + if test "$with_vbox" != "yes"; then + vboxinc="$with_vbox" + fi + ;; + esac +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Check whether --with-vboxlib was given. +if test "${with_vboxlib+set}" = set; then : + withval=$with_vboxlib; case $with_vboxlib in + no) + ;; + yes|*) + vbox="yes" + if test "$with_vboxlib" != "yes"; then + vboxlib="$with_vboxlib" + fi + ;; + esac +fi + +# vbox support yes? +if test "$vbox" = "yes"; then + vboxinc=`echo $vboxinc` + vboxlib=`echo $vboxlib` + if test ! -d "$vboxinc"; then + as_fn_error $? "not directory: $vboxinc" "$LINENO" 5 + fi + if test ! -d "$vboxlib"; then + as_fn_error $? "not directory: $vboxlib" "$LINENO" 5 + fi + CPPFLAGS="$CPPFLAGS -I$vboxinc" + LDFLAGS="$LDFLAGS -Wl,-rpath,$vboxlib" + LIBS="$LIBS $vboxlib/VBoxDDU.so $vboxlib/VBoxRT.so" + +$as_echo "#define USE_VBOXVD 1" >>confdefs.h + + # define vbox include version + + vbox_major=`$SED -e '/^VBOX_VERSION_MAJOR[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + vbox_minor=`$SED -e '/^VBOX_VERSION_MINOR[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + vbox_build=`$SED -e '/^VBOX_VERSION_BUILD[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + + +cat >>confdefs.h <<_ACEOF +#define ISTGT_VBOXINC_VERSION_MAJOR $vbox_major +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define ISTGT_VBOXINC_VERSION_MINOR $vbox_minor +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define ISTGT_VBOXINC_VERSION_BUILD $vbox_build +_ACEOF + +fi + +# check for PTHREAD_MUTEX_ADAPTIVE_NP +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_MUTEX_ADAPTIVE_NP" >&5 +$as_echo_n "checking for PTHREAD_MUTEX_ADAPTIVE_NP... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + + return (PTHREAD_MUTEX_ADAPTIVE_NP); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +for ac_header in sys/types.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_TYPES_H 1 +_ACEOF + +fi + +done + +for ac_header in machine/atomic.h +do : + ac_fn_c_check_header_compile "$LINENO" "machine/atomic.h" "ac_cv_header_machine_atomic_h" "#if HAVE_SYS_TYPES_H +#include +#endif + +" +if test "x$ac_cv_header_machine_atomic_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MACHINE_ATOMIC_H 1 +_ACEOF + +fi + +done + +for ac_header in sys/atomic.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/atomic.h" "ac_cv_header_sys_atomic_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_atomic_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_ATOMIC_H 1 +_ACEOF + +fi + +done + + +# for FeeeBSD +#AC_CHECK_FUNCS([atomic_store_rel_int atomic_load_acq_int]) +#AC_CHECK_FUNCS([atomic_cmpset_ptr atomic_cmpset_64 atomic_cmpset_32]) + +# for NetBSD +#AC_CHECK_FUNCS([atomic_swap_uint atomic_or_uint_nv]) +#AC_CHECK_FUNCS([atomic_cas_ptr atomic_cas_64 atomic_cas_32]) + +atomic="no" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic operations" >&5 +$as_echo_n "checking for atomic operations... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +int +main () +{ + + int x, y; + atomic_store_rel_int(&x, 1); + y = atomic_load_acq_int(&x); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define USE_ATOMIC 1" >>confdefs.h + + +$as_echo "#define HAVE_ATOMIC_STORE_REL_INT 1" >>confdefs.h + + +$as_echo "#define HAVE_ATOMIC_LOAD_ACQ_INT 1" >>confdefs.h + +atomic="yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test $atomic = "no"; then +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +int +main () +{ + + unsigned int x, y; + atomic_swap_uint(&x, 1); + y = atomic_or_uint_nv(&x, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define USE_ATOMIC 1" >>confdefs.h + + +$as_echo "#define HAVE_ATOMIC_SWAP_UINT 1" >>confdefs.h + + +$as_echo "#define HAVE_ATOMIC_OR_UINT_NV 1" >>confdefs.h + +atomic="yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +int +main () +{ + + membar_producer(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define HAVE_MEMBAR_PRODUCER 1" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $atomic" >&5 +$as_echo "$atomic" >&6; } + +# for gcc builtin +#AC_CHECK_FUNCS([__sync_fetch_and_add __sync_val_compare_and_swap]) +#AC_CHECK_FUNCS([__sync_synchronize]) + +gcc_atomic="no" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc builtin atomic operations" >&5 +$as_echo_n "checking for gcc builtin atomic operations... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if HAVE_SYS_TYPES_H +#include +#endif + +int +main () +{ + + unsigned int x, y; + y = __sync_fetch_and_add(&x, 0); + __sync_val_compare_and_swap(&x, y, 2); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define USE_GCC_ATOMIC 1" >>confdefs.h + + +$as_echo "#define HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT 1" >>confdefs.h + + +$as_echo "#define HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT 1" >>confdefs.h + +gcc_atomic="yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if HAVE_SYS_TYPES_H +#include +#endif + +int +main () +{ + + __sync_synchronize(); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define HAVE_GCC_ATOMIC_SYNCHRONIZE 1" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_atomic" >&5 +$as_echo "$gcc_atomic" >&6; } + +ac_config_files="$ac_config_files Makefile src/Makefile etc/Makefile doc/Makefile" + +ac_config_files="$ac_config_files src/build.h" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by istgt $as_me 0.5, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +istgt config.status 0.5 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "src/build.h") CONFIG_FILES="$CONFIG_FILES src/build.h" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..beabb6ed --- /dev/null +++ b/configure.in @@ -0,0 +1,389 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.62]) +AC_INIT([istgt], [0.5]) +AC_CONFIG_SRCDIR([src/istgt.c]) +AC_CONFIG_HEADERS([src/config.h]) + +# Checks for programs. +AC_PROG_CC([clang gcc cc]) +AC_PROG_INSTALL +AC_PROG_RANLIB +AC_PROG_SED +AC_PROG_MKDIR_P + +# clagn with -O3 +if test "$CC" = "clang" && test "$ac_test_CFLAGS" != "set"; then + CFLAGS="-g -O3" +fi + +# host OS related +vboxinc="/usr/local/src/virtualbox/*/include" +vboxlib="/usr/local/lib/virtualbox" +AC_SUBST([rctemplate], [""]) +AC_SUBST([rcdir], ['${prefix}/etc/rc.d']) +AC_CANONICAL_HOST +case "$host_os" in +*linux*) + tmp="/usr/src/virtualbox/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + fi + vboxlib="/usr/lib/virtualbox" + AC_SUBST([rctemplate], ["istgt_linux.sh.in"]) + AC_SUBST([rcdir], ['/etc/init.d']) + AC_DEFINE([_GNU_SOURCE], 1, [Define if linux host]) + ;; +*netbsd*) + AC_SUBST([rctemplate], ["istgt_netbsd.sh.in"]) + AC_SUBST([rcdir], ['/etc/rc.d']) + ;; +*freebsd*) + tmp="/usr/ports/emulators/virtualbox-ose/work/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + else + tmp="/usr/ports/emulators/virtualbox-ose-legacy/work/*/include" + if test -d "`echo $tmp`"; then + vboxinc=$tmp + fi + fi + vboxlib="/usr/local/lib/virtualbox" + AC_SUBST([rctemplate], ["istgt.sh.in"]) + AC_SUBST([rcdir], ['${prefix}/etc/rc.d']) + if test "$mandir" = '${datarootdir}/man'; then + AC_SUBST([mandir], ['${prefix}/man']) + fi + ;; +esac + +# Checks for libraries. +AC_CHECK_LIB([pthread], [pthread_create]) +AC_CHECK_LIB([crypto], [MD5_Update]) + +# Checks for header files. +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_STRUCT_ST_BLOCKS +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([ftruncate memset realpath socket strcasecmp strchr strncasecmp strspn strtol strtoull]) + +# check compatibility +AC_SYS_LARGEFILE +AC_CHECK_HEADERS([aio.h sched.h uuid.h sys/disk.h sys/disklabel.h]) +AC_CHECK_HEADERS([pthread.h]) +AC_CHECK_HEADERS([pthread_np.h], [], [], +[#if HAVE_PTHREAD_H +#include +#endif +]) +AC_CHECK_FUNCS([strlcpy arc4random srandomdev pthread_yield sched_yield]) +AC_CHECK_FUNCS([pthread_set_name_np setproctitle]) +AC_SUBST([MKDEP]) +AC_PATH_PROG([MKDEP], ["mkdep"]) +#if test -z "$MKDEP"; then +# AC_PATH_PROG([MKDEP], ["makedepend"]) +#fi + +# paths +configdir="$ac_default_prefix/etc/istgt" +mediadir="/var/istgt" +if test "$prefix" != "NONE"; then + configdir="$prefix/etc/istgt" +fi +AC_ARG_WITH([configdir], + AS_HELP_STRING([--with-configdir=DIR], [(default PREFIX/etc/istgt)]), + [case $withval in + yes|no) + ;; + *) + configdir="$withval" + ;; + esac]) +AC_SUBST([configdir]) +AC_ARG_WITH([mediadir], + AS_HELP_STRING([--with-mediadir=DIR], [(default /var/istgt)]), + [case $withval in + yes|no) + ;; + *) + mediadir="$withval" + ;; + esac]) +AC_SUBST([mediadir]) + +# startup script directory +AC_ARG_WITH([rcdir], + AS_HELP_STRING([--with-rcdir=DIR], [(default PREFIX/etc/rc.d)]), + [case $withval in + yes|no) + ;; + *) + rcdir="$withval" + ;; + esac]) +AC_SUBST([rcdir]) + +# test for -Wall +saved_CFLAGS="$CFLAGS" +AC_MSG_CHECKING([whether the C compiler accepts -Wall]) +CFLAGS="$CFLAGS -Wall" +AC_TRY_COMPILE(,, + AC_MSG_RESULT(yes); saved_CFLAGS="$CFLAGS", + AC_MSG_RESULT(no)) +CFLAGS="$saved_CFLAGS" + +# test for -Wextra +saved_CFLAGS="$CFLAGS" +AC_MSG_CHECKING([whether the C compiler accepts -Wextra]) +CFLAGS="$CFLAGS -Wextra" +AC_TRY_COMPILE(,, + AC_MSG_RESULT(yes); saved_CFLAGS="$CFLAGS", + AC_MSG_RESULT(no)) +CFLAGS="$saved_CFLAGS" + +# check enable features +AC_MSG_CHECKING([whether to use debug mode]) +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug], [enable debug(logging)]), + AC_MSG_RESULT(yes); AC_DEFINE([DEBUG], 1, [Define if enable debug]), + AC_MSG_RESULT(no)) +AC_SUBST([DEBUG]) + +AC_MSG_CHECKING([whether to use symlink device]) +AC_ARG_ENABLE([symlink-device], + AS_HELP_STRING([--enable-symlink-device], [allow symlink device]), + AC_MSG_RESULT(yes); AC_DEFINE([ALLOW_SYMLINK_DEVICE], 1, [Define if enable symlink-device]), + AC_MSG_RESULT(no)) +AC_SUBST([ALLOW_SYMLINK_DEVICE]) + +AC_MSG_CHECKING([which syslog facility to use]) +AC_ARG_WITH([logfacility], + AS_HELP_STRING([--with-logfacility], [syslog facility to log with (default "local7")]), + [case $with_logfacility in + daemon|auth|authpriv|local0|local1|local2|local3|local4|local5|local6|local7) + logfacility=$with_logfacility + ;; + *) AC_MSG_ERROR(["unsupported facility $with_logfacility"]) + ;; + esac], + [logfacility="local7"]) +AC_DEFINE_UNQUOTED([DEFAULT_LOG_FACILITY], ["$logfacility"], [syslog facility]) +AC_MSG_RESULT("$logfacility") + +AC_MSG_CHECKING([which syslog priority to use]) +AC_ARG_WITH([logpriority], + AS_HELP_STRING([--with-logpriority], [syslog priority to log with (default "info")]), + [case $with_logpriority in + emerg|alert|crit|err|warning|notice|info|debug) + logpriority=$with_logpriority + ;; + *) AC_MSG_ERROR(["unsupported priority $with_logpriority"]) + ;; + esac], + [logpriority="info"]) +AC_DEFINE_UNQUOTED([DEFAULT_LOG_PRIORITY], ["$logpriority"], [syslog priority]) +AC_MSG_RESULT("$logpriority") + +#AC_MSG_CHECKING([whether to use asynchronous io]) +#AC_ARG_WITH([aio], +# AS_HELP_STRING([--with-aio], [use aio (default "no")]), +# [case $with_aio in +# yes) +# AC_DEFINE([USE_AIO], 1, [use aio]) +# AC_MSG_RESULT(yes) +# ;; +# *) +# AC_MSG_RESULT(no) +# ;; +# esac], +# AC_MSG_RESULT(no)) +#AC_SUBST([USE_AIO]) + +# vbox support +vbox="no" +AC_MSG_CHECKING([VirtualBox Virtual Disk support]) +AC_ARG_WITH([vbox], + AS_HELP_STRING([--with-vbox=INC], [VirtualBox include]), + [case $with_vbox in + no) + AC_MSG_RESULT([no]) + ;; + yes|*) + AC_MSG_RESULT([yes]) + vbox="yes" + if test "$with_vbox" != "yes"; then + vboxinc="$with_vbox" + fi + ;; + esac], + [AC_MSG_RESULT([no])]) +AC_ARG_WITH([vboxlib], + AS_HELP_STRING([--with-vboxlib=LIB], [VirtualBox lib]), + [case $with_vboxlib in + no) + ;; + yes|*) + vbox="yes" + if test "$with_vboxlib" != "yes"; then + vboxlib="$with_vboxlib" + fi + ;; + esac], + []) +# vbox support yes? +if test "$vbox" = "yes"; then + vboxinc=`echo $vboxinc` + vboxlib=`echo $vboxlib` + if test ! -d "$vboxinc"; then + AC_MSG_ERROR([not directory: $vboxinc]) + fi + if test ! -d "$vboxlib"; then + AC_MSG_ERROR([not directory: $vboxlib]) + fi + CPPFLAGS="$CPPFLAGS -I$vboxinc" + LDFLAGS="$LDFLAGS -Wl,-rpath,$vboxlib" + LIBS="$LIBS $vboxlib/VBoxDDU.so $vboxlib/VBoxRT.so" + AC_DEFINE([USE_VBOXVD], 1, [Use vbox virtual disk support]) + # define vbox include version + changequote(<<, >>) + vbox_major=`$SED -e '/^VBOX_VERSION_MAJOR[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + vbox_minor=`$SED -e '/^VBOX_VERSION_MINOR[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + vbox_build=`$SED -e '/^VBOX_VERSION_BUILD[ ]*=/!d' -e 's/.*=[^0-9]*\([0-9]*\).*/\1/' $vboxinc/../Config.kmk` + changequote([, ]) + AC_DEFINE_UNQUOTED([ISTGT_VBOXINC_VERSION_MAJOR], [$vbox_major], [VBox include major]) + AC_DEFINE_UNQUOTED([ISTGT_VBOXINC_VERSION_MINOR], [$vbox_minor], [VBox include minor]) + AC_DEFINE_UNQUOTED([ISTGT_VBOXINC_VERSION_BUILD], [$vbox_build], [VBox include build]) +fi + +# check for PTHREAD_MUTEX_ADAPTIVE_NP +AC_MSG_CHECKING([for PTHREAD_MUTEX_ADAPTIVE_NP]) +AC_TRY_COMPILE([ +#include +], +[ + return (PTHREAD_MUTEX_ADAPTIVE_NP); +], +[AC_MSG_RESULT([yes]) +AC_DEFINE([HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [1], [Define 1 if you have the value.])], +[AC_MSG_RESULT([no])] +) + +AC_CHECK_HEADERS([sys/types.h]) +AC_CHECK_HEADERS([machine/atomic.h], [], [], +[#if HAVE_SYS_TYPES_H +#include +#endif +]) +AC_CHECK_HEADERS([sys/atomic.h]) + +# for FeeeBSD +#AC_CHECK_FUNCS([atomic_store_rel_int atomic_load_acq_int]) +#AC_CHECK_FUNCS([atomic_cmpset_ptr atomic_cmpset_64 atomic_cmpset_32]) + +# for NetBSD +#AC_CHECK_FUNCS([atomic_swap_uint atomic_or_uint_nv]) +#AC_CHECK_FUNCS([atomic_cas_ptr atomic_cas_64 atomic_cas_32]) + +atomic="no" +AC_MSG_CHECKING([for atomic operations]) +AC_TRY_LINK([ +#if HAVE_SYS_TYPES_H +#include +#endif +#include +], +[ + int x, y; + atomic_store_rel_int(&x, 1); + y = atomic_load_acq_int(&x); +], +[AC_DEFINE([USE_ATOMIC], [1], [Use atomic]) +AC_DEFINE([HAVE_ATOMIC_STORE_REL_INT], [1], [Define 1 if you have the function.]) +AC_DEFINE([HAVE_ATOMIC_LOAD_ACQ_INT], [1], [Define 1 if you have the function.]) +atomic="yes"] +) +if test $atomic = "no"; then +AC_TRY_LINK([ +#if HAVE_SYS_TYPES_H +#include +#endif +#include +], +[ + unsigned int x, y; + atomic_swap_uint(&x, 1); + y = atomic_or_uint_nv(&x, 0); +], +[AC_DEFINE([USE_ATOMIC], [1], [Use atomic]) +AC_DEFINE([HAVE_ATOMIC_SWAP_UINT], [1], [Define 1 if you have the function.]) +AC_DEFINE([HAVE_ATOMIC_OR_UINT_NV], [1], [Define 1 if you have the function.]) +atomic="yes"] +) +fi +AC_TRY_LINK([ +#if HAVE_SYS_TYPES_H +#include +#endif +#include +], +[ + membar_producer(); +], +[AC_DEFINE([HAVE_MEMBAR_PRODUCER], [1], [Define 1 if you have the function.])] +) +AC_MSG_RESULT($atomic) + +# for gcc builtin +#AC_CHECK_FUNCS([__sync_fetch_and_add __sync_val_compare_and_swap]) +#AC_CHECK_FUNCS([__sync_synchronize]) + +gcc_atomic="no" +AC_MSG_CHECKING([for gcc builtin atomic operations]) +AC_TRY_LINK([ +#if HAVE_SYS_TYPES_H +#include +#endif +], +[ + unsigned int x, y; + y = __sync_fetch_and_add(&x, 0); + __sync_val_compare_and_swap(&x, y, 2); +], +[AC_DEFINE([USE_GCC_ATOMIC], [1], [Use gcc builtin atomic]) +AC_DEFINE([HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT], [1], [Define 1 if you have the function.]) +AC_DEFINE([HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT], [1], [Define 1 if you have the function.]) +gcc_atomic="yes"] +) +AC_TRY_LINK([ +#if HAVE_SYS_TYPES_H +#include +#endif +], +[ + __sync_synchronize(); +], +[AC_DEFINE([HAVE_GCC_ATOMIC_SYNCHRONIZE], [1], [Define 1 if you have the function.])] +) +AC_MSG_RESULT($gcc_atomic) + +AC_CONFIG_FILES([Makefile src/Makefile etc/Makefile doc/Makefile]) +AC_CONFIG_FILES([src/build.h]) +AC_OUTPUT diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..cde9d9a8 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,78 @@ +# for doc + +top_srcdir = .. +srcdir = . + +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +sysconfdir = ${prefix}/etc +datarootdir = ${prefix}/share +datadir = ${datarootdir} +libexecdir = ${exec_prefix}/libexec +mandir = ${datarootdir}/man + +configdir = /usr/local/etc/istgt +mediadir = /var/istgt + +SED = /bin/sed +INSTALL = /usr/bin/install -c +MKDIR_P = /bin/mkdir -p + +source = +header = +document = QUICKSTART QUICKSTART.jp istgt.1.in +sample = + +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTFILES = Makefile.in \ + $(header) $(source) \ + $(document) $(sample) + +######################################################################### + +.PHONY: all install install-doc install-dirs install-doc-dirs +all: istgt.1 + +istgt.1: + $(SED) -e 's:%%PREFIX%%:$(prefix):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.1.in > $@ + +dist: $(DISTFILES) + $(MKDIR_P) $(DISTDIR)/$(subdir) + cd $(srcdir); thisdir=`pwd`; \ + for file in $(DISTFILES); do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done + +install: install-dirs + $(INSTALL) -m 0644 istgt.1 $(DESTDIR)$(mandir)/man1/ + -rm -f $(DESTDIR)$(mandir)/man1/istgt.1.gz + gzip -9 $(DESTDIR)$(mandir)/man1/istgt.1 + +install-doc: install-doc-dirs + $(INSTALL) -m 0644 $(top_srcdir)/README $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 $(top_srcdir)/ChangeLog.jp $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 QUICKSTART $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 QUICKSTART.jp $(DESTDIR)$(datadir)/doc/istgt/ + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(mandir)/man1 + +install-doc-dirs: + $(MKDIR_P) $(DESTDIR)$(datadir)/doc/istgt + +.PHONY: clean distclean depend +clean: + -rm -f istgt.1 + -rm -f a.out *.o *.core + -rm -f *~ + +distclean: clean + -rm -f Makefile config.status config.cache config.log config.h + +depend: + +######################################################################### diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..407f234b --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,78 @@ +# for doc + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +libexecdir = @libexecdir@ +mandir = @mandir@ + +configdir = @configdir@ +mediadir = @mediadir@ + +SED = @SED@ +INSTALL = @INSTALL@ +MKDIR_P = @MKDIR_P@ + +source = +header = +document = QUICKSTART QUICKSTART.jp istgt.1.in +sample = + +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTFILES = Makefile.in \ + $(header) $(source) \ + $(document) $(sample) + +######################################################################### + +.PHONY: all install install-doc install-dirs install-doc-dirs +all: istgt.1 + +istgt.1: + $(SED) -e 's:%%PREFIX%%:$(prefix):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.1.in > $@ + +dist: $(DISTFILES) + $(MKDIR_P) $(DISTDIR)/$(subdir) + cd $(srcdir); thisdir=`pwd`; \ + for file in $(DISTFILES); do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done + +install: install-dirs + $(INSTALL) -m 0644 istgt.1 $(DESTDIR)$(mandir)/man1/ + -rm -f $(DESTDIR)$(mandir)/man1/istgt.1.gz + gzip -9 $(DESTDIR)$(mandir)/man1/istgt.1 + +install-doc: install-doc-dirs + $(INSTALL) -m 0644 $(top_srcdir)/README $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 $(top_srcdir)/ChangeLog.jp $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 QUICKSTART $(DESTDIR)$(datadir)/doc/istgt/ + $(INSTALL) -m 0644 QUICKSTART.jp $(DESTDIR)$(datadir)/doc/istgt/ + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(mandir)/man1 + +install-doc-dirs: + $(MKDIR_P) $(DESTDIR)$(datadir)/doc/istgt + +.PHONY: clean distclean depend +clean: + -rm -f istgt.1 + -rm -f a.out *.o *.core + -rm -f *~ + +distclean: clean + -rm -f Makefile config.status config.cache config.log config.h + +depend: + +######################################################################### diff --git a/doc/QUICKSTART b/doc/QUICKSTART new file mode 100644 index 00000000..da94715c --- /dev/null +++ b/doc/QUICKSTART @@ -0,0 +1,51 @@ +Quick Start +----------- + +Copy sample configuration files after installation. + +# cd /usr/local/etc/istgt +# cp auth.conf.sample auth.conf +# cp istgt.conf.sample istgt.conf +# cp istgtcontrol.conf.sample istgtcontrol.conf + +Edit istgt.conf. +3 sections below at least need modification against your own copy of +istgt.conf.sample. + +[PortalGroup1] IP address +[InitiatorGroup1] Initiator name and netmask +[LogicalUnit1] LUN0 allocated file name and size + +[PortalGroup1] + Portal DA1 192.168.2.36:3260 + +Replace 192.168.2.36 with your server IP. +Because 3260 is standard iSCSI port, 3260 does not need modification. + +[InitiatorGroup1] + InitiatorName "iqn.1991-05.com.microsoft:saturn" + Netmask 192.168.2.0/24 + +Replace "iqn.1991-05.com.microsoft:saturn" with your allowed initiator +name and 192.168.2.0/24 with your allowed IP or CIDR. +If you need any initiator names or IPs, use special word ALL instead. + +[LogicalUnit1] + LUN0 Storage /tank/iscsi/istgt-disk1 10GB + +Replace /tank/iscsi/istgt-disk1 with your correct path and 10GB with +the size you want. +You can specify the size also with MB or TB. +When the device file (/dev/ad1, /dev/zvol/tank/vol, etc.) is specified, +Auto can be specified for the size. + +After finishing to edit istgt.conf, start daemon by the script. + +# /usr/local/etc/rc.d/istgt forcestart + +Check messages on terminal and syslog (usually /var/log/messages). +An error message may only appear at syslog. + +Add istgt_enable="YES" to /etc/rc.conf. + +You have done. diff --git a/doc/QUICKSTART.jp b/doc/QUICKSTART.jp new file mode 100644 index 00000000..c6bc65df --- /dev/null +++ b/doc/QUICKSTART.jp @@ -0,0 +1,61 @@ +istgt.confの設定とistgtデーモンの起動 + +Portsからでもtarballからでもインストールを実行すると、 +デフォルトで/usr/local/etc/istgtの中にサンプル定義ファイルが +作成されますのでこれをコピーして起動用の設定を作成します。 + +# cd /usr/local/etc/istgt +# cp auth.conf.sample auth.conf +# cp istgt.conf.sample istgt.conf +# cp istgtcontrol.conf.sample istgtcontrol.conf + +最低修正が必要な場所は以下の3箇所です。 +[PortalGroup1] のサーバIPアドレス +[InitiatorGroup1] のイニシエータ名とネットマスク +[LogicalUnit1] のLUN0に割り当てる領域とサイズ + +[PortalGroup1] + Portal DA1 192.168.2.36:3260 +↑192.168.2.36を利用するサーバのIPアドレスに変更します。 +3260は標準のiSCSIポート番号なので通常は変更する必要はありません。 + +[InitiatorGroup1] + InitiatorName "iqn.1991-05.com.microsoft:saturn" + Netmask 192.168.2.0/24 +↑接続を許可するイニシエータ名とIPアドレスまたはCIDR表記に変更します。 +任意の名前やIPを許可するには特殊ワード ALL を指定します。 + +[LogicalUnit1] + LUN0 Storage /tank/iscsi/istgt-disk1 10GB +↑サンプルではファイル形式(/tank/iscsi/istgt-disk1)で +10GBを割り当てるようになっています。 +環境に合わせてパスを変更し、ディスクの容量を指定します。 +単位はMBやTBで指定することも可能です。 +デバイスファイル(/dev/ad1, /dev/zvol/tank/volなど)を指定する場合は +サイズにAutoを指定できます。 + +設定できたら起動スクリプトを使ってデーモンを起動します。 + +# /usr/local/etc/rc.d/istgt forcestart + +初期化ルーチンのエラーは標準エラー出力に出されますが、 +それ以降のエラーはsyslogに書き込むので/var/log/messagesも確認します。 + +正しく動くようになったら /etc/rc.conf に +istgt_enable="YES" +を加えてサーバ起動時にデーモンも自動起動するように設定します。 + + +LUNに対するアクセス制限は以下のように適用されます。 + +IG(イニシエータグループ)で指定したイニシエータが +ネットマスクで許可されたIPアドレスから、 +PG(ポータルグループ)で指定したネットワークポータル(IP/ポート番号)を通して、 +LU(iSCSI LUN)にアクセスした場合に許可されます。 + +イニシエータ名とIPアドレスの両方もしくはいずれかの設定により +許可するべき範囲を設定できるようになっています。 +現時点では最低1個のアクセス許可を設定しないと起動しません。 + +※LUというのは元々LUN0しか想定していない時代の名残で、 +本来ならLUではなくLUGになるべきかもしれません。 diff --git a/doc/istgt.1.in b/doc/istgt.1.in new file mode 100644 index 00000000..36107689 --- /dev/null +++ b/doc/istgt.1.in @@ -0,0 +1,59 @@ +.TH istgt 1 "Mar 12, 2009" "istgt" +.SH NAME +istgt \- iSCSI target +.SH SYNOPSIS +.B istgt +[options] +.SH DESCRIPTION +.B istgt +is an iSCSI target for FreeBSD 7.1 or later. +It is designed for multipath failover cluster nodes. +Also useful for virtual machine such as Hyper-V, ESXi. +.SH OPTIONS +.TP +.BI \-c " config" +Use specified file as configuration file. +Multiple instance of istgt is allowed for different IP/ports. +.TP +.BI \-p " pidfile" +Use specified file for writing PID of daemon. +Also it can be specified in configuration file. +This option overwrites by setting of configuration file. +.TP +.BI \-l " facility" +Use specific syslog facility. +.TP +.BI \-m " mode" +Use specified operational mode. 0 = traditional (similar to 20100707), +1 = normal (default), 2 = experimental (new feature mode). +.TP +.BI \-t " flag" +Print trace information to standard error. +trace flag (all, net, iscsi, scsi, lu, none) +.TP +.BI \-q +Use quiet mode. The warning message is omitted. +.TP +.BI \-D +The istgt will not detach from tty and run as foreground. +It requires to print tarce information. +.TP +.BI \-H +Show usage +.TP +.BI \-V +Show version +.SH FILES +.PD 0 +.TP +.I %%CONFIGDIR%%/istgt.conf +Configuration file +.TP +.I %%CONFIGDIR%%/auth.conf +Authentication information file +.TP +.I /var/run/istgt.pid +PID of daemon +.PD +.SH AUTHORS +Daisuke Aoyama diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 00000000..845d7972 --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,96 @@ +# for etc + +top_srcdir = .. +srcdir = . + +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +sysconfdir = ${prefix}/etc +datarootdir = ${prefix}/share +datadir = ${datarootdir} +libexecdir = ${exec_prefix}/libexec +mandir = ${datarootdir}/man + +configdir = /usr/local/etc/istgt +mediadir = /var/istgt + +SED = /bin/sed +INSTALL = /usr/bin/install -c +MKDIR_P = /bin/mkdir -p + +source = +header = +document = +sample = auth.conf istgtcontrol.conf \ + istgt.large.conf.in istgt.conf.in \ + istgt.sh.in istgt_netbsd.sh.in istgt_linux.sh.in +rctemplate = istgt_linux.sh.in +rcdir = /etc/init.d +rcfile = $(rctemplate:.sh.in=.sh) + +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTFILES = Makefile.in \ + $(header) $(source) \ + $(document) $(sample) + +######################################################################### + +.PHONY: all install install-dirs +all: istgt.large.conf istgt.conf $(rcfile) + +istgt.large.conf: + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.large.conf.in > $@ +istgt.conf: + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.conf.in > $@ +$(rcfile): + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' \ + -e 's:%%BINDIR%%:$(bindir):g' \ + -e 's:%%SBINDIR%%:$(sbindir):g' < $(rctemplate) > $@ + +.PHONY: dist clean distclean depend +dist: $(DISTFILES) + $(MKDIR_P) $(DISTDIR)/$(subdir) + cd $(srcdir); thisdir=`pwd`; \ + for file in $(DISTFILES); do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done + +install: install-dirs + $(INSTALL) -m 0644 istgt.conf $(DESTDIR)$(sysconfdir)/istgt/istgt.conf.sample + $(INSTALL) -m 0644 istgt.large.conf \ + $(DESTDIR)$(sysconfdir)/istgt/istgt.large.conf.sample + $(INSTALL) -m 0600 auth.conf $(DESTDIR)$(sysconfdir)/istgt/auth.conf.sample + $(INSTALL) -m 0600 istgtcontrol.conf \ + $(DESTDIR)$(sysconfdir)/istgt/istgtcontrol.conf.sample +# $(INSTALL) -m 0555 istgt.sh $(DESTDIR)$(sysconfdir)/rc.d/istgt + if [ "x$(rcfile)" != "x" -a -f "$(rcfile)" ]; then \ + $(INSTALL) -m 0555 $(rcfile) $(DESTDIR)$(rcdir)/istgt; \ + fi + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(sysconfdir)/istgt + if [ -n "$(rcfile)" ] && [ -f "$(rcfile)" ]; then \ + if [ -n "$(DESTDIR)$(rcdir)" ] && [ ! -d "$(DESTDIR)$(rcdir)" ]; then \ + $(MKDIR_P) $(DESTDIR)$(rcdir); \ + fi \ + fi + +clean: + -rm -f istgt.large.conf istgt.conf $(rcfile) + -rm -f a.out *.o *.core + -rm -f *~ + +distclean: clean + -rm -f Makefile config.status config.cache config.log config.h + +depend: + +######################################################################### diff --git a/etc/Makefile.in b/etc/Makefile.in new file mode 100644 index 00000000..057356b7 --- /dev/null +++ b/etc/Makefile.in @@ -0,0 +1,96 @@ +# for etc + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +libexecdir = @libexecdir@ +mandir = @mandir@ + +configdir = @configdir@ +mediadir = @mediadir@ + +SED = @SED@ +INSTALL = @INSTALL@ +MKDIR_P = @MKDIR_P@ + +source = +header = +document = +sample = auth.conf istgtcontrol.conf \ + istgt.large.conf.in istgt.conf.in \ + istgt.sh.in istgt_netbsd.sh.in istgt_linux.sh.in +rctemplate = @rctemplate@ +rcdir = @rcdir@ +rcfile = $(rctemplate:.sh.in=.sh) + +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTFILES = Makefile.in \ + $(header) $(source) \ + $(document) $(sample) + +######################################################################### + +.PHONY: all install install-dirs +all: istgt.large.conf istgt.conf $(rcfile) + +istgt.large.conf: + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.large.conf.in > $@ +istgt.conf: + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' < istgt.conf.in > $@ +$(rcfile): + $(SED) -e 's:%%SYSCONFDIR%%:$(sysconfdir):g' \ + -e 's:%%CONFIGDIR%%:$(configdir):g' \ + -e 's:%%MEDIADIR%%:$(mediadir):g' \ + -e 's:%%BINDIR%%:$(bindir):g' \ + -e 's:%%SBINDIR%%:$(sbindir):g' < $(rctemplate) > $@ + +.PHONY: dist clean distclean depend +dist: $(DISTFILES) + $(MKDIR_P) $(DISTDIR)/$(subdir) + cd $(srcdir); thisdir=`pwd`; \ + for file in $(DISTFILES); do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done + +install: install-dirs + $(INSTALL) -m 0644 istgt.conf $(DESTDIR)$(sysconfdir)/istgt/istgt.conf.sample + $(INSTALL) -m 0644 istgt.large.conf \ + $(DESTDIR)$(sysconfdir)/istgt/istgt.large.conf.sample + $(INSTALL) -m 0600 auth.conf $(DESTDIR)$(sysconfdir)/istgt/auth.conf.sample + $(INSTALL) -m 0600 istgtcontrol.conf \ + $(DESTDIR)$(sysconfdir)/istgt/istgtcontrol.conf.sample +# $(INSTALL) -m 0555 istgt.sh $(DESTDIR)$(sysconfdir)/rc.d/istgt + if [ "x$(rcfile)" != "x" -a -f "$(rcfile)" ]; then \ + $(INSTALL) -m 0555 $(rcfile) $(DESTDIR)$(rcdir)/istgt; \ + fi + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(sysconfdir)/istgt + if [ -n "$(rcfile)" ] && [ -f "$(rcfile)" ]; then \ + if [ -n "$(DESTDIR)$(rcdir)" ] && [ ! -d "$(DESTDIR)$(rcdir)" ]; then \ + $(MKDIR_P) $(DESTDIR)$(rcdir); \ + fi \ + fi + +clean: + -rm -f istgt.large.conf istgt.conf $(rcfile) + -rm -f a.out *.o *.core + -rm -f *~ + +distclean: clean + -rm -f Makefile config.status config.cache config.log config.h + +depend: + +######################################################################### diff --git a/etc/auth.conf b/etc/auth.conf new file mode 100644 index 00000000..2f6f0968 --- /dev/null +++ b/etc/auth.conf @@ -0,0 +1,24 @@ +# authentication information +# +# do not forget to change permission of this file +# and remove sample users :-) +# +# currntly, this file is read at each authentication +# +[AuthGroup1] + Comment "Auth Group1" + # User Secret MutualUser MutualSecret (Mutual is optional) + # chap secret length is from 12 to 16 (for MS initiator) +# Auth "iqn.1991-05.com.microsoft:saturn" "1234567890abcdef" \ +# "iqn.2007-09.jp.ne.peach:disk1" "mutualtestxx" +# Auth "iqn.1991-05.com.microsoft:athena" "abcdefghijklmnop" + +# tag 9999 is defined as AuthGroup for Dicsovery in sample istgt.conf +[AuthGroup9999] +# Auth "iqn.1991-05.com.microsoft:saturn" "testchaptest" \ +# "iqn.2007-09.jp.ne.peach:disk1" "mutualtestxx" + +# tag 10000 is defined as AuthGroup for UnitControl in sample istgt.conf +[AuthGroup10000] + Comment "Unit Controller's users" + Auth "testuser" "secret" "mutual user" "mutual secret" diff --git a/etc/istgt.conf.in b/etc/istgt.conf.in new file mode 100644 index 00000000..5cbc719d --- /dev/null +++ b/etc/istgt.conf.in @@ -0,0 +1,180 @@ +# istgt configuration file +# +# Please do not write parameters excluding ASCII. +# The parameter must be quoted if space or separator include. +# +# The section of PortalGroup, InitiatorGroup and LogicalUnit can be +# reloaded by sending SIGHUP to the istgt process. +# +# configuration syntax: +# spaces at head of line are deleted, other spaces are as separator +# starting with '#' is comment line, not evaluate +# ending with '\' is concatenating next line +# bracket key is section key grouping following keys +# group number of section key is used as tag number +# (group number might not be continuous value) +# 1st string is key may appear multiple times +# 2nd and more are value associated the key +# Comment key is placed for human readable like user interface +# +[Global] + Comment "Global section" + # node name (not include optional part) + NodeBase "iqn.2007-09.jp.ne.peach.istgt" + + # files + PidFile /var/run/istgt.pid + AuthFile %%CONFIGDIR%%/auth.conf + + # directories + # for removable media (virtual DVD/virtual Tape) + MediaDirectory %%MEDIADIR%% + + # syslog facility + LogFacility "local7" + + # socket I/O timeout sec. (polling is infinity) + Timeout 30 + # NOPIN sending interval sec. + NopInInterval 20 + + # authentication information for discovery session + DiscoveryAuthMethod Auto + #DiscoveryAuthGroup AuthGroup9999 + + # reserved maximum connections and sessions + # NOTE: iSCSI boot is 2 or more sessions required + MaxSessions 16 + MaxConnections 4 + + # maximum number of sending R2T in each connection + # actual number is limited to QueueDepth and MaxCmdSN and ExpCmdSN + # 0=disabled, 1-256=improves large writing + MaxR2T 32 + + # iSCSI initial parameters negotiate with initiators + # NOTE: incorrect values might crash + MaxOutstandingR2T 16 + DefaultTime2Wait 2 + DefaultTime2Retain 60 + FirstBurstLength 262144 + MaxBurstLength 1048576 + MaxRecvDataSegmentLength 262144 + + # NOTE: not supported + InitialR2T Yes + ImmediateData Yes + DataPDUInOrder Yes + DataSequenceInOrder Yes + ErrorRecoveryLevel 0 + +[UnitControl] + Comment "Internal Logical Unit Controller" + #AuthMethod Auto + AuthMethod CHAP Mutual + AuthGroup AuthGroup10000 + # this portal is only used as controller (by istgtcontrol) + # if it's not necessary, no portal is valid + #Portal UC1 [::1]:3261 + Portal UC1 127.0.0.1:3261 + # accept IP netmask + #Netmask [::1] + Netmask 127.0.0.1 + +# You should set IPs in /etc/rc.conf for physical I/F +[PortalGroup1] + Comment "SINGLE PORT TEST" + # Portal Label(not used) IP(IPv6 or IPv4):Port + #Portal DA1 [2001:03e0:06cf:0003:021b:21ff:fe04:f405]:3260 + Portal DA1 192.168.2.36:3260 + +# wildcard address you may need if use DHCP +# DO NOT USE WITH OTHER PORTALS +#[PortalGroup1] +# Comment "ANY IP" +# # Portal Label(not used) IP(IPv6 or IPv4):Port +# #Portal DA1 [::]:3260 +# Portal DA1 0.0.0.0:3260 + +[InitiatorGroup1] + Comment "Initiator Group1" + # name with ! deny login/discovery + #InitiatorName "!iqn.1991-05.com.microsoft:moon" + # spetified name allow login/discovery + #InitiatorName "iqn.1991-05.com.microsoft:saturn" + # special word "ALL" match all of initiators + InitiatorName "ALL" + Netmask 192.168.2.0/24 + +# TargetName, Mapping, UnitType, LUN0 are minimum required +[LogicalUnit1] + Comment "Hard Disk Sample" + # full specified iqn (same as below) + #TargetName iqn.2007-09.jp.ne.peach.istgt:disk1 + # short specified non iqn (will add NodeBase) + TargetName disk1 + TargetAlias "Data Disk1" + # use initiators in tag1 via portals in tag1 + Mapping PortalGroup1 InitiatorGroup1 + # accept both CHAP and None + AuthMethod Auto + AuthGroup AuthGroup1 + #UseDigest Header Data + UseDigest Auto + UnitType Disk + # SCSI INQUIRY - Vendor(8) Product(16) Revision(4) Serial(16) + #UnitInquiry "FreeBSD" "iSCSI Disk" "0123" "10000001" + # Queuing 0=disabled, 1-255=enabled with specified depth. + #QueueDepth 32 + + # override global setting if need + #MaxOutstandingR2T 16 + #DefaultTime2Wait 2 + #DefaultTime2Retain 60 + #FirstBurstLength 262144 + #MaxBurstLength 1048576 + #MaxRecvDataSegmentLength 262144 + #InitialR2T Yes + #ImmediateData Yes + #DataPDUInOrder Yes + #DataSequenceInOrder Yes + #ErrorRecoveryLevel 0 + + # LogicalVolume for this unit on LUN0 + # for file extent + LUN0 Storage /tank/iscsi/istgt-disk1 10GB + # for raw device extent + #LUN0 Storage /dev/ad4 Auto + # for ZFS volume extent + #LUN0 Storage /dev/zvol/tank/istgt-vol1 Auto + + # override the serial of LUN0 specified with UnitInquiry + #LUN0 Option Serial "10000001" + + # for 3.5inch, 7200rpm HDD + # RPM 0=not reported, 1=non-rotating(SSD), n>1024 rpm + #LUN0 Option RPM 7200 + # FormFactor 0=not reported, 1=5.25, 2=3.5, 3=2.5, 4=1.8, 5=less 1.8 inch + #LUN0 Option FormFactor 2 + + # for 2.5inch, SSD + #LUN0 Option RPM 1 + #LUN0 Option FormFactor 3 + + # for future use (enabled by default) + #LUN0 Option ReadCache Disable + + # control WCE(mode page 8) and O_FSYNC/O_SYNC on the backing store (enabled by default) + #LUN0 Option WriteCache Disable + +#[LogicalUnit2] +# # SCSI commands pass through to SCSI device by CAM +# Comment "Pass-through Disk Sample" +# TargetName pass-disk1 +# TargetAlias "Pass Through Disk1" +# Mapping PortalGroup1 InitiatorGroup1 +# AuthMethod Auto +# AuthGroup AuthGroup1 +# UnitType Pass +# # DO NOT SPECIFY PARTITION, PASS-THROUGH USE ENTIRE LOGICAL UNIT +# LUN0 Device /dev/da0 diff --git a/etc/istgt.large.conf.in b/etc/istgt.large.conf.in new file mode 100644 index 00000000..07f17a51 --- /dev/null +++ b/etc/istgt.large.conf.in @@ -0,0 +1,310 @@ +# istgt configuration file +# +# Please do not write parameters excluding ASCII. +# The parameter must be quoted if space or separator include. +# +# configuration syntax: +# spaces at head of line are deleted, other spaces are as separator +# starting with '#' is comment line, not evaluate +# ending with '\' is concatenating next line +# bracket key is section key grouping following keys +# group number of section key is used as tag number +# (group number might not be continuous value) +# 1st string is key may appear multiple times +# 2nd and more are value associated the key +# Comment key is placed for human readable like user interface +# +[Global] + Comment "Global section" + # node name (not include optional part) + NodeBase "iqn.2007-09.jp.ne.peach.istgt" + + # files + PidFile /var/run/istgt.pid + AuthFile %%CONFIGDIR%%/auth.conf + + # directories + # for removable media (virtual DVD/virtual Tape) + #MediaDirectory /mnt + MediaDirectory %%MEDIADIR%% + #MediaDirectory /tank/iscsi + + # syslog facility + LogFacility "local7" + + # socket I/O timeout sec. (polling is infinity) + Timeout 30 + # NOPIN sending interval sec. + NopInInterval 20 + + # authentication information for discovery session + DiscoveryAuthMethod Auto + #DiscoveryAuthMethod CHAP + #DiscoveryAuthGroup AuthGroup9999 + + # reserved maximum connections and sessions + # NOTE: iSCSI boot is 2 or more sessions required + MaxSessions 16 + MaxConnections 4 + + # maximum number of sending R2T in each connection + # actual number is limited to QueueDepth and MaxCmdSN and ExpCmdSN + # 0=disabled, 1-256=improves large writing + MaxR2T 32 + + # iSCSI initial parameters negotiate with initiators + # NOTE: incorrect values might crash + MaxOutstandingR2T 16 + DefaultTime2Wait 2 + DefaultTime2Retain 60 + FirstBurstLength 262144 + MaxBurstLength 1048576 + MaxRecvDataSegmentLength 262144 + + # NOTE: not supported + InitialR2T Yes + ImmediateData Yes + DataPDUInOrder Yes + DataSequenceInOrder Yes + ErrorRecoveryLevel 0 + +[UnitControl] + Comment "Internal Logical Unit Controller" + #AuthMethod Auto + AuthMethod CHAP Mutual + AuthGroup AuthGroup10000 + # this portal is only used as controller (by istgtcontrol) + # if it's not necessary, no portal is valid + #Portal UC1 [::1]:3261 + Portal UC1 127.0.0.1:3261 + #Portal UC1 192.168.2.36:3261 + # accept IP netmask + #Netmask [::1] + Netmask 127.0.0.1 + #Netmask 192.168.2.0/24 + #Netmask 192.168.2.36/32 + +# You should set IPs in /etc/rc.conf for physical I/F +[PortalGroup1] + Comment "DUAL CONTROLLER TEST" + # Portal Label(not used) IP(IPv6 or IPv4):Port + Portal DA1 192.168.3.36:3260 + Portal DA2 192.168.4.36:3260 + Portal DB1 192.168.3.37:3260 + Portal DB2 192.168.4.37:3260 + +[PortalGroup2] + Comment "IPv6 TEST" + Portal DA1 [2001:03e0:06cf:0003:021b:21ff:fe04:f405]:3260 + Portal DA2 [2001:03e0:06cf:0004:021f:d0ff:fe16:38bd]:3260 + #Portal DA3 [2001:380:e00:5:203:47ff:fe72:34f2]:3260 + +[PortalGroup3] + Comment "SINGLE PORT TEST" + Portal DA1 192.168.2.36:3260 + +[PortalGroup10] + Comment "SINGLE PORT TEST" + Portal DA1 192.168.2.37:3260 + +# wildcard address you may need if use DHCP +# DO NOT USE WITH OTHER PORTALS +#[PortalGroup4] +# Comment "ANY IP" +# #Portal DA1 [::]:3260 +# Portal DA1 0.0.0.0:3260 + +[InitiatorGroup1] + # initiator group1 + Comment "Initiator Group1" + InitiatorName "iqn.1991-05.com.microsoft:ceres" + InitiatorName "iqn.1991-05.com.microsoft:saturn" + Netmask 192.168.3.0/24 + Netmask 192.168.4.0/24 + +[InitiatorGroup2] + # initiator group2 + Comment "Initiator Group2" + InitiatorName "iqn.1991-05.com.microsoft:athena" + InitiatorName "iqn.1991-05.com.microsoft:venus" + InitiatorName "iqn.1991-05.com.microsoft:saturn" + Netmask [2001:3e0:6cf:2::]/64 + Netmask [2001:380:e00:5::]/64 + +[InitiatorGroup3] + InitiatorName "iqn.1991-05.com.microsoft:saturn" + Netmask 192.168.2.0/24 + +[InitiatorGroup4] + Comment "ALL initiators from 192.168.2.0/24" + # name with ! deny login/discovery + #InitiatorName "!iqn.1991-05.com.microsoft:moon" + # spetified name allow login/discovery + #InitiatorName "iqn.1991-05.com.microsoft:saturn" + # special word "ALL" match all of initiators + InitiatorName ALL + Netmask 192.168.2.0/24 + +[InitiatorGroup5] + Comment "Initiator Group5" + InitiatorName "iqn.2007-09.jp.ne.peach:pluto" + Netmask 192.168.2.0/24 + Netmask 192.168.3.0/24 + Netmask 192.168.4.0/24 + Netmask [2001:3e0:6cf:2::]/64 + Netmask [2001:380:e00:5::]/64 + +[InitiatorGroup6] + InitiatorName "iqn.2008-04.com.sun.virtualbox.initiator" + Netmask 192.168.2.0/24 + +[InitiatorGroup256] + Comment "ALL initiators from ALL IP" + InitiatorName ALL + Netmask ALL + +# TargetName, Mapping, UnitType, LUN0 are minimum required +[LogicalUnit1] + Comment "Hard Disk Sample" + # full specified iqn (same as below) + #TargetName iqn.2007-09.jp.ne.peach.istgt:disk1 + # short specified non iqn (will add NodeBase) + TargetName disk1 + TargetAlias "Data Disk1" + # use both portal group tag1 and tag3 for initiator tag1 + Mapping PortalGroup3 InitiatorGroup1 + Mapping PortalGroup1 InitiatorGroup1 + #Mapping PortalGroup2 InitiatorGroup2 + #AuthMethod CHAP Mutual + AuthMethod CHAP + #AuthMethod Auto + AuthGroup AuthGroup1 + # force use digest Header/Data/Auto + UseDigest Header Data + #UseDigest Header + #UseDigest Data + #UseDigest Auto + ReadOnly No + UnitType Disk + UnitOnline Yes + # SCSI INQUIRY - Vendor(8) Product(16) Revision(4) Serial(16) + #UnitInquiry "FreeBSD" "iSCSI Disk" "0123" "10000001" + # one of 512,1024,2048,4096 (default 512 is strongly recommended) + #BlockLength 512 + # Queuing 0=disabled, 1-255=enabled with specified depth. + #QueueDepth 32 + + # override global setting if need + #MaxOutstandingR2T 16 + #DefaultTime2Wait 2 + #DefaultTime2Retain 60 + #FirstBurstLength 262144 + #MaxBurstLength 1048576 + #MaxRecvDataSegmentLength 262144 + #InitialR2T Yes + #ImmediateData Yes + #DataPDUInOrder Yes + #DataSequenceInOrder Yes + #ErrorRecoveryLevel 0 + + # LogicalVolume for this unit on LUN0 + # for file extent + LUN0 Storage /tank/iscsi/istgt-disk1 10GB + # for raw device extent + #LUN0 Storage /dev/ad4 Auto + # for ZFS volume extent + #LUN0 Storage /dev/zvol/tank/istgt-vol1 Auto + # override the serial of LUN0 specified with UnitInquiry + #LUN0 Option Serial "10000001" + + # for 3.5inch, 7200rpm HDD + # RPM 0=not reported, 1=non-rotating(SSD), n>1024 rpm + LUN0 Option RPM 7200 + # FormFactor 0=not reported, 1=5.25, 2=3.5, 3=2.5, 4=1.8, 5=less 1.8 inch + LUN0 Option FormFactor 2 + + # for 2.5inch, SSD + #LUN0 Option RPM 1 + #LUN0 Option FormFactor 3 + + # for future use (enabled by default) + #LUN0 Option ReadCache Disable + #LUN0 Option WriteCache Disable + + #LUN1 Storage /tank/iscsi/istgt-disk1.1 10GB + #LUN1 Option Serial "10000001L1" + LUN2 Storage /tank/iscsi/istgt-disk1.2 10GB + #LUN2 Option Serial "10000001L2" + +[LogicalUnit2] + Comment "Hard Disk Sample" + #TargetName disk2 + TargetName iqn.1994-04.org.netbsd.iscsi-target:target11 + TargetAlias "iSCSI Boot Disk" + # use portal group tag1/2/3 for initiator tag5 + Mapping PortalGroup1 InitiatorGroup5 + Mapping PortalGroup2 InitiatorGroup5 + Mapping PortalGroup3 InitiatorGroup5 + AuthMethod Auto + AuthGroup None + #AuthMethod CHAP Mutual + #UseDigest Header Data + UseDigest Auto + ReadOnly No + UnitType Disk + UnitOnline Yes + # you can specify one of '+' or '-' value + LUN0 Storage /tank/iscsi/istgt-disk2 20GB-1MB + # 2PB-1MB is maximum for current windows GUI manager + #LUN1 Storage /tank/iscsi/istgt-disk2.1 2PB-1MB + # probably 8EB is seek limit on FreeBSD + #LUN2 Storage /tank/iscsi/istgt-disk2.2 8EB-1 + +[LogicalUnit3] + Comment "DVD ROM sample" + TargetName dvd1 + #TargetName iqn.1994-04.org.netbsd.iscsi-target:target44 + TargetAlias "DVD ROM Drive1" + Mapping PortalGroup3 InitiatorGroup4 + AuthMethod Auto + UseDigest Auto + ReadOnly Yes + UnitType DVD + UnitOnline Yes + #UnitInquiry "NetBSD" "iSCSI DVDROM" "0" + #UnitInquiry "FreeBSD" "iSCSI DVDROM" "0001" "10000003" + # auto size is depend on actual file size + LUN0 Removable ro /tank/iscsi/dvds/dvd1.iso auto + +[LogicalUnit4] + Comment "DLT sample" + TargetName tape1 + TargetAlias "Tape Drive1" + Mapping PortalGroup3 InitiatorGroup4 + AuthMethod Auto + UseDigest Auto + ReadOnly No + UnitType Tape + UnitOnline Yes + #UnitInquiry "QUANTUM" "DLT8000" "C001" "CX10000001" + LUN0 Removable "rw" /tank/iscsi/tapes/tape1.vt 1GB + # extend file size if EOM reached + #LUN1 Removable "rw,extend" /tank/iscsi/tapes/tape1.vt 1GB + # file size grow and shrink automatically by EOF (ignore specified size) + #LUN2 Removable "rw,dynamic" /tank/iscsi/tapes/tape1.vt auto + +[LogicalUnit10] + Comment "Hard Disk Sample" + TargetName disk3 + Mapping PortalGroup3 InitiatorGroup6 + UnitType Disk + # currently zvol is slow due to ZIL commit + LUN0 Storage /dev/zvol/tank/istgt-vol1 20GB + +[LogicalUnit11] + Comment "Hard Disk Sample" + TargetName disk4 + Mapping PortalGroup10 InitiatorGroup5 + UnitType Disk + LUN0 Storage /tank/iscsi/istgt-disk4 16GB + diff --git a/etc/istgt.sh.in b/etc/istgt.sh.in new file mode 100644 index 00000000..2dde3945 --- /dev/null +++ b/etc/istgt.sh.in @@ -0,0 +1,24 @@ +#!/bin/sh + +# PROVIDE: istgt +# REQUIRE: NETWORKING syslogd mountlate +# BEFORE: LOGIN +# KEYWORD: shutdown + +. /etc/rc.subr + +name="istgt" +rcvar=istgt_enable +extra_commands="reload" + +load_rc_config $name + +: ${istgt_enable:="NO"} +: ${istgt_config:="%%CONFIGDIR%%/${name}.conf"} + +required_files="${istgt_config}" +pidfile=${istgt_pidfile:-"/var/run/${name}.pid"} +command="%%BINDIR%%/${name}" +command_args="-c ${istgt_config}" + +run_rc_command "$1" diff --git a/etc/istgt_linux.sh.in b/etc/istgt_linux.sh.in new file mode 100644 index 00000000..ffc746a4 --- /dev/null +++ b/etc/istgt_linux.sh.in @@ -0,0 +1,62 @@ +#!/bin/sh +# +### BEGIN INIT INFO +# Provides: istgt +# Required-Start: $remote_fs $syslog $named +# Required-Stop: $remote_fs $syslog +# Should-Start: network-remotefs +# Should-Stop: network-remotefs +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Userspace iSCSI target daemon +# Description: Userspace iSCSI target daemon +### END INIT INFO + +. /etc/rc.status +rc_reset + +name="istgt" + +: ${istgt_config="%%SYSCONFDIR%%/istgt/istgt.conf"} +: ${istgt_pidfile="/var/run/istgt.pid"} +: ${istgt_flags=""} + +required_files="${istgt_config}" +pidfile="${istgt_pidfile}" +command="%%SBINDIR%%/istgt" +command_args="-c ${istgt_config} ${istgt_flags}" + +case "$1" in + start) + echo "Starting iSCSI target daemon (${name})" + startproc $command $command_args + rc_status -v + ;; + stop) + echo "Shutting down iSCSI target daemon (${name})" + killproc -p $istgt_pidfile -TERM $command + rc_status -v + rm -f $istgt_pidfile 2>/dev/null + ;; + restart) + $0 stop + $0 start + rc_status + ;; + force-reload|reload) + echo "Reloading iSCSI target daemon (${name})" + killproc -p $istgt_pidfile -HUP $command + rc_status -v + ;; + status) + echo "Checking for iSCSI target daemon (${name})" + checkproc -p $istgt_pidfile $command + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac + +rc_exit diff --git a/etc/istgt_netbsd.sh.in b/etc/istgt_netbsd.sh.in new file mode 100644 index 00000000..eae96d3e --- /dev/null +++ b/etc/istgt_netbsd.sh.in @@ -0,0 +1,18 @@ +#!/bin/sh + +# PROVIDE: istgt +# REQUIRE: NETWORKING syslogd mountall +# BEFORE: LOGIN +# KEYWORD: shutdown + +. /etc/rc.subr + +name="istgt" +rcvar=$name +command="%%BINDIR%%/${name}" +required_files="%%CONFIGDIR%%/${name}.conf" +pidfile="/var/run/${name}.pid" +extra_commands="reload" + +load_rc_config $name +run_rc_command "$1" diff --git a/etc/istgtcontrol.conf b/etc/istgtcontrol.conf new file mode 100644 index 00000000..b3937570 --- /dev/null +++ b/etc/istgtcontrol.conf @@ -0,0 +1,31 @@ +# istgtcontrol configuration file +# +[Global] + Comment "sample configuration" + # default values can be overrided by command line switch. + + # socket I/O timeout sec. + Timeout 60 + + # authentication information + #AuthMethod Auto + AuthMethod CHAP Mutual + Auth "testuser" "secret" "mutual user" "mutual secret" + #AuthMethod CHAP + #Auth "testuser" "secret" + + # default controller's host name or IP and port + Host localhost + #Host 192.168.2.36 + Port 3261 + + # default target name and LUN + #TargetName "iqn.xxxx" + TargetName "iqn.2007-09.jp.ne.peach:dvd1" + Lun 0 + + # removable file's flag, initial size if creating + # ro: read only, rw: read and write + # auto: use existing size or minimum size + Flags "ro" + Size "auto" diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..377bb868 --- /dev/null +++ b/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..53b1a4b4 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,139 @@ +######################################################################### +# Makefile for istgt +######################################################################### + +top_srcdir = .. +srcdir = . +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +sysconfdir = ${prefix}/etc +datarootdir = ${prefix}/share +datadir = ${datarootdir} +libexecdir = ${exec_prefix}/libexec +mandir = ${datarootdir}/man + +CC = clang +SUBPROGRAM = +CFLAGS = -g -O3 -Wall -Wextra +CPPFLAGS = -I$(top_srcdir) -I$(srcdir) +LDFLAGS = +DEFS = -DHAVE_CONFIG_H +LIBS = -lcrypto -lpthread -lkqueue +INSTALL = /usr/bin/install -c +MKDIR_P = /bin/mkdir -p +RANLIB = ranlib +MKDEP = + +CFLAGS += -DDEBUG -ggdb3 +CFLAGS += -fno-strict-aliasing -Wstrict-aliasing +CFLAGS += -Wformat=2 -Wreturn-type +CFLAGS += -Wbad-function-cast +CFLAGS += -Wcast-qual -Wchar-subscripts -Winline +CFLAGS += -Wmissing-prototypes -Wnested-externs -Wpointer-arith +CFLAGS += -Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings +CFLAGS += -Wno-error=cast-align + +source = istgt.c istgt_iscsi.c istgt_iscsi_param.c \ + istgt_lu.c istgt_cmd_table.c istgt_ser_table.c istgt_lu_disk.c istgt_lu_disk_xcopy.c istgt_lu_disk_vbox.c \ + istgt_lu_ctl.c \ + istgt_log.c istgt_conf.c istgt_sock.c istgt_misc.c \ + istgt_queue.c istgt_crc32c.c istgt_md5.c +header = istgt_ver.h istgt.h istgt_iscsi.h istgt_iscsi_xcopy.h istgt_iscsi_param.h \ + istgt_scsi.h istgt_proto.h istgt_lu.h \ + istgt_log.h istgt_conf.h istgt_sock.h \ + istgt_misc.h istgt_queue.h istgt_crc32c.h istgt_md5.h +document = +sample = + +ctl_source = istgtcontrol.c istgt_conf.c istgt_log.c istgt_sock.c istgt_misc.c \ + istgt_md5.c +ctl_header = istgt_ver.h istgt_conf.h istgt_log.h istgt_sock.h istgt_misc.h \ + istgt_md5.h + +ISTGT = $(source:.c=.o) +ISTGTCONTROL = $(ctl_source:.c=.o) + +PACKAGE_NAME = istgt +PACKAGE_STRING = istgt 0.5 +PACKAGE_TARNAME = istgt +PACKAGE_VERSION = 0.5 + +VER_H = istgt_ver.h +DISTBASE = istgt +DISTVER = `sed -e '/ISTGT_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +DISTEXTVER = `sed -e '/ISTGT_EXTRA_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +#DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) +#DISTDIR = $(DISTBASE)-$(DISTVER)-$(DISTEXTVER) +#DISTDIR = $(DISTBASE)-$(DISTEXTVER) +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTNAME = $(DISTDIR).tar.gz +DISTFILES = Makefile.in config.h.in build.h.in \ + $(header) $(source) $(ctl_header) $(ctl_source) \ + $(document) $(sample) + +######################################################################### + +.SUFFIXES: .c .o +.c.o: + $(CC) $(DEFS) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +.PHONY: all install install-dirs + +default: all; + +istgt: $(ISTGT) + $(CC) $(LDFLAGS) -o ${@}.full $(ISTGT) $(LIBS) + objcopy --only-keep-debug ${@}.full ${@}.debug + objcopy --strip-debug --add-gnu-debuglink=${@}.debug ${@}.full ${@} + +istgtcontrol: $(ISTGTCONTROL) + $(CC) $(LDFLAGS) -o ${@}.full $(ISTGTCONTROL) $(LIBS) + objcopy --only-keep-debug ${@}.full ${@}.debug + objcopy --strip-debug --add-gnu-debuglink=${@}.debug ${@}.full ${@} + +all: stamp-depend config.h $(SUBPROGRAM) istgtcontrol istgt + +install: install-dirs + $(INSTALL) -m 0755 istgt $(DESTDIR)$(bindir) + $(INSTALL) -m 0755 istgtcontrol $(DESTDIR)$(bindir) + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(bindir) + +.PHONY: dist clean distclean depend +dist: $(DISTFILES) + if [ -f "$(top_srcdir)/distdir" ]; then \ + $(MKDIR_P) $(DISTDIR)/$(subdir) \ + cd $(srcdir); thisdir=`pwd`; \ + for file in `echo $(DISTFILES) | sort`; do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done \ + fi + +depend: + if [ "x$(MKDEP)" != "x" ]; then \ + $(MKDEP) -MM $(DEFS) $(CFLAGS) $(CPPFLAGS) $(source); \ + fi + touch stamp-depend + +clean: + -rm -f a.out *.o *.core + -rm -f *~ + -rm -f istgt istgtcontrol + -rm -f istgt.debug istgtcontrol.debug + -rm -f istgt.full istgtcontrol.full + +distclean: clean + -rm -f stamp-depend .depend + -rm -f stamp-h.in + -rm -f Makefile config.status config.cache config.log config.h + -rm -f build.h + +######################################################################### + +stamp-depend: Makefile + $(MAKE) depend + +######################################################################### diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 00000000..c01baa02 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,139 @@ +######################################################################### +# Makefile for istgt +######################################################################### + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +libexecdir = @libexecdir@ +mandir = @mandir@ + +CC = @CC@ +SUBPROGRAM = @SUBPROGRAM@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir) -I$(srcdir) +LDFLAGS = @LDFLAGS@ +DEFS = @DEFS@ +LIBS = @LIBS@ +INSTALL = @INSTALL@ +MKDIR_P = @MKDIR_P@ +RANLIB = @RANLIB@ +MKDEP = @MKDEP@ + +CFLAGS += -DDEBUG -ggdb3 +CFLAGS += -fno-strict-aliasing -Wstrict-aliasing +CFLAGS += -Wformat=2 -Wreturn-type +CFLAGS += -Wbad-function-cast +CFLAGS += -Wcast-qual -Wchar-subscripts -Winline +CFLAGS += -Wmissing-prototypes -Wnested-externs -Wpointer-arith +CFLAGS += -Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings +CFLAGS += -Wno-error=cast-align + +source = istgt.c istgt_iscsi.c istgt_iscsi_param.c \ + istgt_lu.c istgt_cmd_table.c istgt_ser_table.c istgt_lu_disk.c istgt_lu_disk_xcopy.c istgt_lu_disk_vbox.c \ + istgt_lu_ctl.c \ + istgt_log.c istgt_conf.c istgt_sock.c istgt_misc.c \ + istgt_queue.c istgt_crc32c.c istgt_md5.c +header = istgt_ver.h istgt.h istgt_iscsi.h istgt_iscsi_xcopy.h istgt_iscsi_param.h \ + istgt_scsi.h istgt_proto.h istgt_lu.h \ + istgt_log.h istgt_conf.h istgt_sock.h \ + istgt_misc.h istgt_queue.h istgt_crc32c.h istgt_md5.h +document = +sample = + +ctl_source = istgtcontrol.c istgt_conf.c istgt_log.c istgt_sock.c istgt_misc.c \ + istgt_md5.c +ctl_header = istgt_ver.h istgt_conf.h istgt_log.h istgt_sock.h istgt_misc.h \ + istgt_md5.h + +ISTGT = $(source:.c=.o) +ISTGTCONTROL = $(ctl_source:.c=.o) + +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ + +VER_H = istgt_ver.h +DISTBASE = istgt +DISTVER = `sed -e '/ISTGT_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +DISTEXTVER = `sed -e '/ISTGT_EXTRA_VERSION/!d' -e 's/[^0-9.]*\([0-9.a-z]*\).*/\1/' $(VER_H)` +#DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) +#DISTDIR = $(DISTBASE)-$(DISTVER)-$(DISTEXTVER) +#DISTDIR = $(DISTBASE)-$(DISTEXTVER) +DISTDIR = $(top_srcdir)/`cat $(top_srcdir)/distdir` +DISTNAME = $(DISTDIR).tar.gz +DISTFILES = Makefile.in config.h.in build.h.in \ + $(header) $(source) $(ctl_header) $(ctl_source) \ + $(document) $(sample) + +######################################################################### + +.SUFFIXES: .c .o +.c.o: + $(CC) $(DEFS) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +.PHONY: all install install-dirs + +default: all; + +istgt: $(ISTGT) + $(CC) $(LDFLAGS) -o ${@}.full $(ISTGT) $(LIBS) + objcopy --only-keep-debug ${@}.full ${@}.debug + objcopy --strip-debug --add-gnu-debuglink=${@}.debug ${@}.full ${@} + +istgtcontrol: $(ISTGTCONTROL) + $(CC) $(LDFLAGS) -o ${@}.full $(ISTGTCONTROL) $(LIBS) + objcopy --only-keep-debug ${@}.full ${@}.debug + objcopy --strip-debug --add-gnu-debuglink=${@}.debug ${@}.full ${@} + +all: stamp-depend config.h $(SUBPROGRAM) istgtcontrol istgt + +install: install-dirs + $(INSTALL) -m 0755 istgt $(DESTDIR)$(bindir) + $(INSTALL) -m 0755 istgtcontrol $(DESTDIR)$(bindir) + +install-dirs: + $(MKDIR_P) $(DESTDIR)$(bindir) + +.PHONY: dist clean distclean depend +dist: $(DISTFILES) + if [ -f "$(top_srcdir)/distdir" ]; then \ + $(MKDIR_P) $(DISTDIR)/$(subdir) \ + cd $(srcdir); thisdir=`pwd`; \ + for file in `echo $(DISTFILES) | sort`; do \ + cp -p $$thisdir/$$file $(DISTDIR)/$(subdir); \ + done \ + fi + +depend: + if [ "x$(MKDEP)" != "x" ]; then \ + $(MKDEP) -MM $(DEFS) $(CFLAGS) $(CPPFLAGS) $(source); \ + fi + touch stamp-depend + +clean: + -rm -f a.out *.o *.core + -rm -f *~ + -rm -f istgt istgtcontrol + -rm -f istgt.debug istgtcontrol.debug + -rm -f istgt.full istgtcontrol.full + +distclean: clean + -rm -f stamp-depend .depend + -rm -f stamp-h.in + -rm -f Makefile config.status config.cache config.log config.h + -rm -f build.h + +######################################################################### + +stamp-depend: Makefile + $(MAKE) depend + +######################################################################### diff --git a/src/build.h b/src/build.h new file mode 100644 index 00000000..c91e5348 --- /dev/null +++ b/src/build.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008-2011 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BUILD_H +#define BUILD_H + +#define BUILD_PREFIX "/usr/local" +#define BUILD_ETC_ISTGT "/usr/local/etc/istgt" +#define BUILD_VAR_ISTGT "/var/istgt" + +#endif /* BUILD_H */ diff --git a/src/build.h.in b/src/build.h.in new file mode 100644 index 00000000..1d7982fc --- /dev/null +++ b/src/build.h.in @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008-2011 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BUILD_H +#define BUILD_H + +#define BUILD_PREFIX "@prefix@" +#define BUILD_ETC_ISTGT "@configdir@" +#define BUILD_VAR_ISTGT "@mediadir@" + +#endif /* BUILD_H */ diff --git a/src/config.h b/src/config.h new file mode 100644 index 00000000..d08f14ba --- /dev/null +++ b/src/config.h @@ -0,0 +1,323 @@ +/* src/config.h. Generated from config.h.in by configure. */ +/* src/config.h.in. Generated from configure.in by autoheader. */ + +/* Define if enable symlink-device */ +/* #undef ALLOW_SYMLINK_DEVICE */ + +/* Define if enable debug */ +/* #undef DEBUG */ + +/* syslog facility */ +#define DEFAULT_LOG_FACILITY "local7" + +/* syslog priority */ +#define DEFAULT_LOG_PRIORITY "info" + +/* Define to 1 if you have the header file. */ +#define HAVE_AIO_H 1 + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define 1 if you have the function. */ +/* #undef HAVE_ATOMIC_LOAD_ACQ_INT */ + +/* Define 1 if you have the function. */ +/* #undef HAVE_ATOMIC_OR_UINT_NV */ + +/* Define 1 if you have the function. */ +/* #undef HAVE_ATOMIC_STORE_REL_INT */ + +/* Define 1 if you have the function. */ +/* #undef HAVE_ATOMIC_SWAP_UINT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define 1 if you have the function. */ +#define HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT 1 + +/* Define 1 if you have the function. */ +#define HAVE_GCC_ATOMIC_SYNCHRONIZE 1 + +/* Define 1 if you have the function. */ +#define HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `cam' library (-lcam). */ +/* #undef HAVE_LIBCAM */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_ATOMIC_H */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define 1 if you have the function. */ +/* #undef HAVE_MEMBAR_PRODUCER */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define 1 if you have the value. */ +#define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTHREAD_NP_H */ + +/* Define to 1 if you have the `pthread_set_name_np' function. */ +/* #undef HAVE_PTHREAD_SET_NAME_NP */ + +/* Define to 1 if you have the `pthread_yield' function. */ +#define HAVE_PTHREAD_YIELD 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `sched_yield' function. */ +#define HAVE_SCHED_YIELD 1 + +/* Define to 1 if you have the `setproctitle' function. */ +/* #undef HAVE_SETPROCTITLE */ + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the `srandomdev' function. */ +/* #undef HAVE_SRANDOMDEV */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strspn' function. */ +#define HAVE_STRSPN 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoull' function. */ +#define HAVE_STRTOULL 1 + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#define HAVE_ST_BLOCKS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ATOMIC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISKLABEL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UUID_H */ + +/* VBox include build */ +/* #undef ISTGT_VBOXINC_VERSION_BUILD */ + +/* VBox include major */ +/* #undef ISTGT_VBOXINC_VERSION_MAJOR */ + +/* VBox include minor */ +/* #undef ISTGT_VBOXINC_VERSION_MINOR */ + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "istgt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "istgt 0.5" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "istgt" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.5" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Use atomic */ +/* #undef USE_ATOMIC */ + +/* Use gcc builtin atomic */ +#define USE_GCC_ATOMIC 1 + +/* Use vbox virtual disk support */ +/* #undef USE_VBOXVD */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define if linux host */ +#define _GNU_SOURCE 1 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 00000000..5f5780fe --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,322 @@ +/* src/config.h.in. Generated from configure.in by autoheader. */ + +/* Define if enable symlink-device */ +#undef ALLOW_SYMLINK_DEVICE + +/* Define if enable debug */ +#undef DEBUG + +/* syslog facility */ +#undef DEFAULT_LOG_FACILITY + +/* syslog priority */ +#undef DEFAULT_LOG_PRIORITY + +/* Define to 1 if you have the header file. */ +#undef HAVE_AIO_H + +/* Define to 1 if you have the `arc4random' function. */ +#undef HAVE_ARC4RANDOM + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define 1 if you have the function. */ +#undef HAVE_ATOMIC_LOAD_ACQ_INT + +/* Define 1 if you have the function. */ +#undef HAVE_ATOMIC_OR_UINT_NV + +/* Define 1 if you have the function. */ +#undef HAVE_ATOMIC_STORE_REL_INT + +/* Define 1 if you have the function. */ +#undef HAVE_ATOMIC_SWAP_UINT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define 1 if you have the function. */ +#undef HAVE_GCC_ATOMIC_FETCH_AND_ADD_UINT + +/* Define 1 if you have the function. */ +#undef HAVE_GCC_ATOMIC_SYNCHRONIZE + +/* Define 1 if you have the function. */ +#undef HAVE_GCC_ATOMIC_VAL_COMPARE_AND_SWAP_UINT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `cam' library (-lcam). */ +#undef HAVE_LIBCAM + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACHINE_ATOMIC_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define 1 if you have the function. */ +#undef HAVE_MEMBAR_PRODUCER + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define 1 if you have the value. */ +#undef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_NP_H + +/* Define to 1 if you have the `pthread_set_name_np' function. */ +#undef HAVE_PTHREAD_SET_NAME_NP + +/* Define to 1 if you have the `pthread_yield' function. */ +#undef HAVE_PTHREAD_YIELD + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the header file. */ +#undef HAVE_SCHED_H + +/* Define to 1 if you have the `sched_yield' function. */ +#undef HAVE_SCHED_YIELD + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the `srandomdev' function. */ +#undef HAVE_SRANDOMDEV + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strspn' function. */ +#undef HAVE_STRSPN + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#undef HAVE_ST_BLOCKS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ATOMIC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DISKLABEL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DISK_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UUID_H + +/* VBox include build */ +#undef ISTGT_VBOXINC_VERSION_BUILD + +/* VBox include major */ +#undef ISTGT_VBOXINC_VERSION_MAJOR + +/* VBox include minor */ +#undef ISTGT_VBOXINC_VERSION_MINOR + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Use atomic */ +#undef USE_ATOMIC + +/* Use gcc builtin atomic */ +#undef USE_GCC_ATOMIC + +/* Use vbox virtual disk support */ +#undef USE_VBOXVD + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define if linux host */ +#undef _GNU_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `long int' if does not define. */ +#undef off_t + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to `int' if does not define. */ +#undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t diff --git a/src/istgt.c b/src/istgt.c new file mode 100644 index 00000000..5133f7fd --- /dev/null +++ b/src/istgt.c @@ -0,0 +1,2977 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include +#include + +#ifdef __FreeBSD__ +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + +#include +#include + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_conf.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_crc32c.h" +#include "istgt_iscsi.h" +#include "istgt_lu.h" +#include "istgt_proto.h" + +#include + + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#define POLLWAIT 5000 +#define PORTNUMLEN 32 + +ISTGT g_istgt; + +/* + * Global - number of luworker threads per lun + */ +int g_num_luworkers; + +static int +istgt_parse_portal(const char *portal, char **host, char **port, int *que) +{ + const char *p; + int n; + int ret; + if (portal == NULL) { + ISTGT_ERRLOG("portal error\n"); + return -1; + } + if (host == NULL || port == NULL || que == NULL) { + return 0; + } + + if (portal[0] == '[') { + /* IPv6 */ + p = strchr(portal + 1, ']'); + if (p == NULL) { + ISTGT_ERRLOG("portal error\n"); + return -1; + } + p++; + n = p - portal; + if (host != NULL) { + *host = xmalloc(n + 1); + memcpy(*host, portal, n); + (*host)[n] = '\0'; + } + if (p[0] == '\0') { + if (port != NULL) { + *port = xmalloc(PORTNUMLEN); + snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT); + } + } else { + if (p[0] != ':') { + ISTGT_ERRLOG("portal error\n"); + if (host != NULL) + xfree(*host); + return -1; + } + if (port != NULL) + *port = xstrdup(p + 1); + } + } else { + /* IPv4 */ + /*p = strchr(portal, ':'); + if (p == NULL) { + p = portal + strlen(portal); + } + n = p - portal; + if (host != NULL) { + *host = xmalloc(n + 1); + memcpy(*host, portal, n); + (*host)[n] = '\0'; + } + if (p[0] == '\0') { + if (port != NULL) { + *port = xmalloc(PORTNUMLEN); + snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT); + } + } else { + if (p[0] != ':') { + ISTGT_ERRLOG("portal error\n"); + if (host != NULL) + xfree(*host); + return -1; + } + if (port != NULL) + *port = xstrdup(p + 1); + }*/ + + + *host = xmalloc(64); + *port = xmalloc(32); + if (*host == NULL || *port == NULL) { + ISTGT_ERRLOG("portal:%s alloc failed\n", portal); + return -1; + } + *que = 32; + ret = sscanf(portal, "%64[^:]:%32[^:]:%d", *host, *port, que); + if (ret == 2) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "portal host:%s port:%s q:--\n", *host, *port); + } else if (ret == 3) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "portal host:%s port:%s q:%d\n", *host, *port, *que); + } else { + ISTGT_ERRLOG("portal:%s ret:%d host:%s port:%s q:%d\n", portal, ret, *host, *port, *que); + } + } + return 0; +} + +static int +istgt_add_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx) +{ + const char *val; + char *label, *portal, *host, *port; + int que; + int alloc_len; + int idx, free_idx; + int portals; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add portal group %d\n", sp->num); + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + /* counts number of definition */ + for (i = 0; ; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) + break; + rc = istgt_parse_portal(portal, NULL, NULL, NULL); + if (rc < 0) { + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + } + portals = i; + if (portals > MAX_PORTAL) { + ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals); + return -1; + } + + MTX_LOCK(&istgt->mutex); + idx = istgt->nportal_group; + free_idx = -1; + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag != 0) + continue; + if (istgt->portal_group[i].nportals == portals) { + free_idx = i; + break; + } + } + if (free_idx >= 0) + idx = free_idx; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Tag=%d, Portals=%d\n", + idx, sp->num, portals); + if (idx < MAX_PORTAL_GROUP) { + if (free_idx < 0) { + istgt->portal_group[idx].nportals = portals; + alloc_len = sizeof (PORTAL *) * portals; + istgt->portal_group[idx].portals = xmalloc(alloc_len); + } + istgt->portal_group[idx].ref = 0; + istgt->portal_group[idx].idx = idx; + istgt->portal_group[idx].tag = sp->num; + + for (i = 0; i < portals; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) { + if (free_idx < 0) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + } + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("portal error\n"); + return -1; + } + rc = istgt_parse_portal(portal, &host, &port, &que); + if (rc < 0) { + if (free_idx < 0) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + } + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "RIndex=%d, Host=%s, Port=%s, Tag=%d\n", + i, host, port, sp->num); + + if (free_idx < 0) { + istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL)); + } else { + xfree(istgt->portal_group[idx].portals[i]->label); + xfree(istgt->portal_group[idx].portals[i]->host); + xfree(istgt->portal_group[idx].portals[i]->port); + } + istgt->portal_group[idx].portals[i]->label = xstrdup(label); + istgt->portal_group[idx].portals[i]->host = host; + istgt->portal_group[idx].portals[i]->port = port; + istgt->portal_group[idx].portals[i]->que = que; + istgt->portal_group[idx].portals[i]->ref = 0; + istgt->portal_group[idx].portals[i]->idx = i; + istgt->portal_group[idx].portals[i]->tag = sp->num; + istgt->portal_group[idx].portals[i]->sock = -1; + } + + if (pgp_idx != NULL) + *pgp_idx = idx; + if (free_idx < 0) { + idx++; + istgt->nportal_group = idx; + } + } else { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx); + return -1; + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_pg_match_all(PORTAL_GROUP *pgp, CF_SECTION *sp) +{ + char *label, *portal, *host, *port; + int que; + int rc; + int i; + + for (i = 0; i < pgp->nportals; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) + return 0; + rc = istgt_parse_portal(portal, &host, &port, &que); + if (rc < 0) + return 0; + if (strcmp(pgp->portals[i]->label, label) != 0) + return 0; + if (strcmp(pgp->portals[i]->host, host) != 0) + return 0; + if (strcmp(pgp->portals[i]->port, port) != 0) + return 0; + if (pgp->portals[i]->que != que) + return 0; + } + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label != NULL || portal != NULL) + return 0; + return 1; +} + +static int +istgt_update_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx) +{ + const char *val; + char *label, *portal, *host, *port; + int que; + int alloc_len; + int idx, free_idx; + int portals; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update portal group %d\n", sp->num); + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + /* counts number of definition */ + for (i = 0; ; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) + break; + rc = istgt_parse_portal(portal, NULL, NULL, NULL); + if (rc < 0) { + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + } + portals = i; + if (portals > MAX_PORTAL) { + ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals); + return -1; + } + + MTX_LOCK(&istgt->mutex); + idx = -1; + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag == sp->num) { + idx = i; + break; + } + } + if (idx < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("can't find PG%d\n", sp->num); + return -1; + } + if (istgt_pg_match_all(&istgt->portal_group[i], sp)) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for PG%d\n", sp->num); + return 0; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Tag=%d, Portals=%d\n", + idx, sp->num, portals); + if (istgt->portal_group[idx].nportals == portals) { + /* udpate PG */ + for (i = 0; i < portals; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("portal error\n"); + return -1; + } + rc = istgt_parse_portal(portal, &host, &port, &que); + if (rc < 0) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "RIndex=%d, Host=%s, Port=%s, Q=%d, Tag=%d\n", + i, host, port, que, sp->num); + + /* free old PG */ + xfree(istgt->portal_group[idx].portals[i]->label); + xfree(istgt->portal_group[idx].portals[i]->host); + xfree(istgt->portal_group[idx].portals[i]->port); + + /* allocate new PG */ + istgt->portal_group[idx].portals[i]->label = xstrdup(label); + istgt->portal_group[idx].portals[i]->host = host; + istgt->portal_group[idx].portals[i]->port = port; + istgt->portal_group[idx].portals[i]->que = que; + //istgt->portal_group[idx].portals[i]->ref = 0; + //istgt->portal_group[idx].portals[i]->idx = i; + //istgt->portal_group[idx].portals[i]->tag = sp->num; + //istgt->portal_group[idx].portals[i]->sock = -1; + } + if (pgp_idx != NULL) + *pgp_idx = idx; + } else { + /* mark as free */ + istgt->portal_group[*pgp_idx].tag = 0; + + /* allocate new PG */ + idx = istgt->nportal_group; + free_idx = -1; + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag != 0) + continue; + if (istgt->portal_group[i].nportals == portals) { + free_idx = i; + break; + } + } + if (free_idx >= 0) + idx = free_idx; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Tag=%d, Portals=%d -> %d\n", + idx, sp->num, istgt->portal_group[*pgp_idx].nportals, portals); + if (idx < MAX_PORTAL_GROUP) { + if (free_idx < 0) { + istgt->portal_group[idx].nportals = portals; + alloc_len = sizeof (PORTAL *) * portals; + istgt->portal_group[idx].portals = xmalloc(alloc_len); + } + istgt->portal_group[idx].ref = istgt->portal_group[*pgp_idx].ref; + istgt->portal_group[idx].idx = idx; + istgt->portal_group[idx].tag = sp->num; + + for (i = 0; i < portals; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) { + if (free_idx < 0) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + } + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("portal error\n"); + return -1; + } + rc = istgt_parse_portal(portal, &host, &port, &que); + if (rc < 0) { + if (free_idx < 0) { + xfree(istgt->portal_group[idx].portals); + istgt->portal_group[idx].nportals = 0; + } + istgt->portal_group[idx].tag = 0; + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "RIndex=%d, Host=%s, Port=%s, Q=%d, Tag=%d\n", + i, host, port, que, sp->num); + + if (free_idx < 0) { + istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL)); + } else { + xfree(istgt->portal_group[idx].portals[i]->label); + xfree(istgt->portal_group[idx].portals[i]->host); + xfree(istgt->portal_group[idx].portals[i]->port); + } + istgt->portal_group[idx].portals[i]->label = xstrdup(label); + istgt->portal_group[idx].portals[i]->host = host; + istgt->portal_group[idx].portals[i]->port = port; + istgt->portal_group[idx].portals[i]->que = que; + istgt->portal_group[idx].portals[i]->ref = 0; + istgt->portal_group[idx].portals[i]->idx = i; + istgt->portal_group[idx].portals[i]->tag = sp->num; + istgt->portal_group[idx].portals[i]->sock = -1; + } + + if (pgp_idx != NULL) + *pgp_idx = idx; + if (free_idx < 0) { + idx++; + istgt->nportal_group = idx; + } + } else { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx); + return -1; + } + } + MTX_UNLOCK(&istgt->mutex); + return 1; +} + +static int +istgt_build_portal_group_array(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + int rc; + + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_PORTALGROUP) { + if (sp->num == 0) { + ISTGT_ERRLOG("Group 0 is invalid\n"); + return -1; + } + rc = istgt_add_portal_group(istgt, sp, NULL); + if (rc < 0) { + ISTGT_ERRLOG("add_portal_group() failed\n"); + return -1; + } + } + sp = sp->next; + } + return 0; +} + +static void +istgt_destroy_portal_group_array(ISTGT_Ptr istgt) +{ + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_portal_group_array\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + for (j = 0; j < istgt->portal_group[i].nportals; j++) { + xfree(istgt->portal_group[i].portals[j]->label); + xfree(istgt->portal_group[i].portals[j]->host); + xfree(istgt->portal_group[i].portals[j]->port); + xfree(istgt->portal_group[i].portals[j]); + } + xfree(istgt->portal_group[i].portals); + + istgt->portal_group[i].nportals = 0; + istgt->portal_group[i].portals = NULL; + istgt->portal_group[i].ref = 0; + istgt->portal_group[i].idx = i; + istgt->portal_group[i].tag = 0; + } + istgt->nportal_group = 0; + MTX_UNLOCK(&istgt->mutex); +} + +static int +istgt_open_portal_group(PORTAL_GROUP *pgp) +{ + int port; + int sock; + int i; + + for (i = 0; i < pgp->nportals; i++) { + if (pgp->portals[i]->sock < 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "open host %s, port %s, q:%d tag %d\n", + pgp->portals[i]->host, pgp->portals[i]->port, + pgp->portals[i]->que, + pgp->portals[i]->tag); + port = (int)strtol(pgp->portals[i]->port, NULL, 0); + sock = istgt_listen(pgp->portals[i]->host, port, pgp->portals[i]->que); + if (sock < 0) { + ISTGT_ERRLOG("listen error %.64s:%d\n", + pgp->portals[i]->host, port); + return -1; + } + pgp->portals[i]->sock = sock; + } + } + return 0; +} + +static int +istgt_open_all_portals(ISTGT_Ptr istgt) +{ + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_portal\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + rc = istgt_open_portal_group(&istgt->portal_group[i]); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + return -1; + } + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_close_portal_group(PORTAL_GROUP *pgp) +{ + int i; + + for (i = 0; i < pgp->nportals; i++) { + if (pgp->portals[i]->sock >= 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "close host %s, port %s, tag %d\n", + pgp->portals[i]->host, pgp->portals[i]->port, + pgp->portals[i]->tag); + close(pgp->portals[i]->sock); + pgp->portals[i]->sock = -1; + } + } + return 0; +} + +static int +istgt_close_all_portals(ISTGT_Ptr istgt) +{ + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_portal\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + rc = istgt_close_portal_group(&istgt->portal_group[i]); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + return -1; + } + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_add_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp) +{ + const char *val; + int alloc_len; + int idx; + int names; + int masks; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add initiator group %d\n", sp->num); + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + /* counts number of definition */ + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "InitiatorName", i); + if (val == NULL) + break; + } + names = i; + if (names > MAX_INITIATOR) { + ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names); + return -1; + } + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "Netmask", i); + if (val == NULL) + break; + } + masks = i; + if (masks > MAX_NETMASK) { + ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks); + return -1; + } + + MTX_LOCK(&istgt->mutex); + idx = istgt->ninitiator_group; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Tag=%d, Names=%d, Masks=%d\n", + idx, sp->num, names, masks); + if (idx < MAX_INITIATOR_GROUP) { + istgt->initiator_group[idx].ninitiators = names; + alloc_len = sizeof (char *) * names; + istgt->initiator_group[idx].initiators = xmalloc(alloc_len); + istgt->initiator_group[idx].nnetmasks = masks; + alloc_len = sizeof (char *) * masks; + istgt->initiator_group[idx].netmasks = xmalloc(alloc_len); + istgt->initiator_group[idx].ref = 0; + istgt->initiator_group[idx].idx = idx; + istgt->initiator_group[idx].tag = sp->num; + + for (i = 0; i < names; i++) { + val = istgt_get_nval(sp, "InitiatorName", i); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "InitiatorName %s\n", val); + istgt->initiator_group[idx].initiators[i] = xstrdup(val); + } + for (i = 0; i < masks; i++) { + val = istgt_get_nval(sp, "Netmask", i); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val); + istgt->initiator_group[idx].netmasks[i] = xstrdup(val); + } + + idx++; + istgt->ninitiator_group = idx; + } else { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("ninitiator_group(%d) >= MAX_INITIATOR_GROUP\n", idx); + return -1; + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_ig_match_all(INITIATOR_GROUP *igp, CF_SECTION *sp) +{ + const char *val; + int i; + + for (i = 0; i < igp->ninitiators; i++) { + val = istgt_get_nval(sp, "InitiatorName", i); + if (val == NULL) + return 0; + if (strcmp(igp->initiators[i], val) != 0) + return 0; + } + val = istgt_get_nval(sp, "InitiatorName", i); + if (val != NULL) + return 0; + for (i = 0; i < igp->nnetmasks; i++) { + val = istgt_get_nval(sp, "Netmask", i); + if (val == NULL) + return 0; + if (strcmp(igp->netmasks[i], val) != 0) + return 0; + } + val = istgt_get_nval(sp, "Netmask", i); + if (val != NULL) + return 0; + return 1; +} + +static int +istgt_update_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp) +{ + const char *val; + int alloc_len; + int idx; + int names; + int masks; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update initiator group %d\n", sp->num); + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + /* counts number of definition */ + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "InitiatorName", i); + if (val == NULL) + break; + } + names = i; + if (names > MAX_INITIATOR) { + ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names); + return -1; + } + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "Netmask", i); + if (val == NULL) + break; + } + masks = i; + if (masks > MAX_NETMASK) { + ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks); + return -1; + } + + MTX_LOCK(&istgt->mutex); + idx = -1; + for (i = 0; i < istgt->ninitiator_group; i++) { + if (istgt->initiator_group[i].tag == sp->num) { + idx = i; + break; + } + } + if (idx < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("can't find IG%d\n", sp->num); + return -1; + } + if (istgt_ig_match_all(&istgt->initiator_group[i], sp)) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for IG%d\n", sp->num); + return 0; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Tag=%d, Names=%d, Masks=%d\n", + idx, sp->num, names, masks); + + /* free old IG */ + for (i = 0; i < istgt->initiator_group[idx].ninitiators; i++) { + xfree(istgt->initiator_group[idx].initiators[i]); + } + xfree(istgt->initiator_group[idx].initiators); + for (i = 0; i < istgt->initiator_group[idx].nnetmasks; i++) { + xfree(istgt->initiator_group[idx].netmasks[i]); + } + xfree(istgt->initiator_group[idx].netmasks); + + /* allocate new IG */ + istgt->initiator_group[idx].ninitiators = names; + alloc_len = sizeof (char *) * names; + istgt->initiator_group[idx].initiators = xmalloc(alloc_len); + istgt->initiator_group[idx].nnetmasks = masks; + alloc_len = sizeof (char *) * masks; + istgt->initiator_group[idx].netmasks = xmalloc(alloc_len); + //istgt->initiator_group[idx].ref = 0; + //istgt->initiator_group[idx].idx = idx; + //istgt->initiator_group[idx].tag = sp->num; + + /* copy new strings */ + for (i = 0; i < names; i++) { + val = istgt_get_nval(sp, "InitiatorName", i); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "InitiatorName %s\n", val); + istgt->initiator_group[idx].initiators[i] = xstrdup(val); + } + for (i = 0; i < masks; i++) { + val = istgt_get_nval(sp, "Netmask", i); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val); + istgt->initiator_group[idx].netmasks[i] = xstrdup(val); + } + istgt_lu_update_ig(istgt, &istgt->initiator_group[idx]); + MTX_UNLOCK(&istgt->mutex); + return 1; +} + +static int +istgt_build_initiator_group_array(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + int rc; + + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_INITIATORGROUP) { + if (sp->num == 0) { + ISTGT_ERRLOG("Group 0 is invalid\n"); + return -1; + } + rc = istgt_add_initiator_group(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("add_initiator_group() failed\n"); + return -1; + } + } + sp = sp->next; + } + return 0; +} + +static void +istgt_destory_initiator_group_array(ISTGT_Ptr istgt) +{ + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_initiator_group_array\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->ninitiator_group; i++) { + for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) { + xfree(istgt->initiator_group[i].initiators[j]); + } + xfree(istgt->initiator_group[i].initiators); + for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) { + xfree(istgt->initiator_group[i].netmasks[j]); + } + xfree(istgt->initiator_group[i].netmasks); + + istgt->initiator_group[i].ninitiators = 0; + istgt->initiator_group[i].initiators = NULL; + istgt->initiator_group[i].nnetmasks = 0; + istgt->initiator_group[i].netmasks = NULL; + istgt->initiator_group[i].ref = 0; + istgt->initiator_group[i].idx = i; + istgt->initiator_group[i].tag = 0; + } + istgt->ninitiator_group = 0; + MTX_UNLOCK(&istgt->mutex); +} + +static int +istgt_build_uctl_portal(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + const char *val; + char *label, *portal, *host, *port; + int que; + int tag; + int idx; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_build_uctl_portal\n"); + + sp = istgt_find_cf_section(istgt->config, "UnitControl"); + if (sp == NULL) { + ISTGT_ERRLOG("find_cf_section failed()\n"); + return -1; + } + + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "Portal", i); + if (val == NULL) + break; + + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) { + ISTGT_ERRLOG("uctl portal error\n"); + return -1; + } + + rc = istgt_parse_portal(portal, &host, &port, &que); + if (rc < 0) { + ISTGT_ERRLOG("parse uctl portal error\n"); + return -1; + } + + idx = istgt->nuctl_portal; + tag = ISTGT_UC_TAG; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Index=%d, Host=%s, Port=%s, Q=%d, Tag=%d\n", + idx, host, port, que, tag); + if (idx < MAX_UCPORTAL) { + istgt->uctl_portal[idx].label = xstrdup(label); + istgt->uctl_portal[idx].host = host; + istgt->uctl_portal[idx].port = port; + istgt->uctl_portal[idx].que = que; + istgt->uctl_portal[idx].ref = 0; + istgt->uctl_portal[idx].idx = idx; + istgt->uctl_portal[idx].tag = tag; + istgt->uctl_portal[idx].sock = -1; + idx++; + istgt->nuctl_portal = idx; + } else { + ISTGT_ERRLOG("nportal(%d) >= MAX_UCPORTAL\n", idx); + xfree(host); + xfree(port); + return -1; + } + } + + return 0; +} + +static void +istgt_destroy_uctl_portal(ISTGT_Ptr istgt) +{ + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destroy_uctl_portal\n"); + for (i = 0; i < istgt->nuctl_portal; i++) { + xfree(istgt->uctl_portal[i].label); + xfree(istgt->uctl_portal[i].host); + xfree(istgt->uctl_portal[i].port); + + istgt->uctl_portal[i].label = NULL; + istgt->uctl_portal[i].host = NULL; + istgt->uctl_portal[i].port = NULL; + istgt->uctl_portal[i].ref = 0; + istgt->uctl_portal[i].idx = i; + istgt->uctl_portal[i].tag = 0; + } + istgt->nuctl_portal = 0; +} + +static int +istgt_open_uctl_portal(ISTGT_Ptr istgt) +{ + int port; + int sock; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_uctl_portal\n"); + for (i = 0; i < istgt->nuctl_portal; i++) { + if (istgt->uctl_portal[i].sock < 0) { + port = (int)strtol(istgt->uctl_portal[i].port, NULL, 0); + sock = istgt_listen_unx(ISTGT_UCTL_UNXPATH, istgt->uctl_portal[i].que); + if (sock < 0) { + ISTGT_ERRLOG("listen error for unx_domain %s, trying tcp listener\n", ISTGT_UCTL_UNXPATH); + sock = istgt_listen(istgt->uctl_portal[i].host, port, istgt->uctl_portal[i].que); + } + if (sock < 0) { + ISTGT_ERRLOG("listen error %.64s:%d\n", + istgt->uctl_portal[i].host, port); + return -1; + } + istgt->uctl_portal[i].sock = sock; + } + } + return 0; +} + +static int +istgt_close_uctl_portal(ISTGT_Ptr istgt) +{ + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_uctl_portal\n"); + for (i = 0; i < istgt->nuctl_portal; i++) { + if (istgt->uctl_portal[i].sock >= 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, + "close host %s, port %s, tag %d\n", + istgt->uctl_portal[i].host, + istgt->uctl_portal[i].port, + istgt->uctl_portal[i].tag); + close(istgt->uctl_portal[i].sock); + istgt->uctl_portal[i].sock = -1; + } + } + return 0; +} + +static int +istgt_write_pidfile(ISTGT_Ptr istgt) +{ + FILE *fp; + pid_t pid; + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_write_pidfile\n"); + rc = remove(istgt->pidfile); + if (rc != 0) { + if (errno != ENOENT) { + ISTGT_ERRLOG("pidfile remove error %d\n", errno); + return -1; + } + } + fp = fopen(istgt->pidfile, "w"); + if (fp == NULL) { + ISTGT_ERRLOG("pidfile open error %d\n", errno); + return -1; + } + pid = getpid(); + fprintf(fp, "%d\n", (int)pid); + fclose(fp); + return 0; +} + +static void +istgt_remove_pidfile(ISTGT_Ptr istgt) +{ + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_remove_pidfile\n"); + rc = remove(istgt->pidfile); + if (rc != 0) { + ISTGT_ERRLOG("pidfile remove error %d\n", errno); + /* ignore error */ + } +} + +char * +istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2) +{ + CF_ITEM *ip; + CF_VALUE *vp; + int i; + + ip = istgt_find_cf_nitem(sp, key, idx1); + if (ip == NULL) + return NULL; + vp = ip->val; + if (vp == NULL) + return NULL; + for (i = 0; vp != NULL; vp = vp->next) { + if (i == idx2) + return vp->value; + i++; + } + return NULL; +} + +char * +istgt_get_nval(CF_SECTION *sp, const char *key, int idx) +{ + CF_ITEM *ip; + CF_VALUE *vp; + + ip = istgt_find_cf_nitem(sp, key, idx); + if (ip == NULL) + return NULL; + vp = ip->val; + if (vp == NULL) + return NULL; + return vp->value; +} + +char * +istgt_get_val(CF_SECTION *sp, const char *key) +{ + return istgt_get_nval(sp, key, 0); +} + +int +istgt_get_nintval(CF_SECTION *sp, const char *key, int idx) +{ + const char *v; + int value; + + v = istgt_get_nval(sp, key, idx); + if (v == NULL) + return -1; + value = (int)strtol(v, NULL, 10); + return value; +} + +int +istgt_get_intval(CF_SECTION *sp, const char *key) +{ + return istgt_get_nintval(sp, key, 0); +} + +static const char * +istgt_get_log_facility(CONFIG *config) +{ + CF_SECTION *sp; + const char *logfacility; + + sp = istgt_find_cf_section(config, "Global"); + if (sp == NULL) { + return NULL; + } + logfacility = istgt_get_val(sp, "LogFacility"); + if (logfacility == NULL) { + logfacility = DEFAULT_LOG_FACILITY; + } +#if 0 + if (g_trace_flag & ISTGT_TRACE_DEBUG) { + fprintf(stderr, "LogFacility %s\n", logfacility); + } +#endif + + return logfacility; +} + +static int +istgt_init(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + const char *ag_tag; + const char *val; + size_t stacksize; + int ag_tag_i; + int MaxSessions; + int MaxConnections; + int MaxOutstandingR2T; + int DefaultTime2Wait; + int DefaultTime2Retain; + int FirstBurstLength; + int MaxBurstLength; + int MaxRecvDataSegmentLength; + int InitialR2T; + int ImmediateData; + int DataPDUInOrder; + int DataSequenceInOrder; + int ErrorRecoveryLevel; + int timeout; + int nopininterval; + int maxr2t; + int OperationalMode; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init\n"); + sp = istgt_find_cf_section(istgt->config, "Global"); + if (sp == NULL) { + ISTGT_ERRLOG("find_cf_section failed()\n"); + return -1; + } + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + val = istgt_get_val(sp, "PidFile"); + if (val == NULL) { + val = DEFAULT_PIDFILE; + } + istgt->pidfile = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PidFile %s\n", + istgt->pidfile); + + val = istgt_get_val(sp, "AuthFile"); + if (val == NULL) { + val = DEFAULT_AUTHFILE; + } + istgt->authfile = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthFile %s\n", + istgt->authfile); + + val = istgt_get_val(sp, "LogFile"); + if (val == NULL) { + val = DEFAULT_LOG_FILE; + } + istgt->logfile = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LogFile %s\n", + istgt->logfile); +#if 0 + val = istgt_get_val(sp, "MediaFile"); + if (val == NULL) { + val = DEFAULT_MEDIAFILE; + } + istgt->mediafile = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaFile %s\n", + istgt->mediafile); +#endif + +#if 0 + val = istgt_get_val(sp, "LiveFile"); + if (val == NULL) { + val = DEFAULT_LIVEFILE; + } + istgt->livefile = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LiveFile %s\n", + istgt->livefile); +#endif + clear_resv = istgt_get_intval(sp, "ClearResv"); + if(clear_resv < 0) { + clear_resv = 1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "clear_resv = %d", clear_resv); + + val = istgt_get_val(sp, "MediaDirectory"); + if (val == NULL) { + val = DEFAULT_MEDIADIRECTORY; + } + istgt->mediadirectory = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaDirectory %s\n", + istgt->mediadirectory); + + val = istgt_get_val(sp, "NodeBase"); + if (val == NULL) { + val = DEFAULT_NODEBASE; + } + istgt->nodebase = xstrdup(val); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NodeBase %s\n", + istgt->nodebase); + + OperationalMode = istgt_get_intval(sp, "OperationalMode"); + if(OperationalMode < 1) { + OperationalMode = DEFAULT_OPERATIONAL_MODE; + } + istgt->OperationalMode = OperationalMode; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Operational mode %s\n", + (istgt->OperationalMode)? "Fake_Mode_Of_Operation" : "Normal_Mode_Of_Operation"); + + MaxSessions = istgt_get_intval(sp, "MaxSessions"); + if (MaxSessions < 1) { + MaxSessions = DEFAULT_MAX_SESSIONS; + } + istgt->MaxSessions = MaxSessions; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxSessions %d\n", + istgt->MaxSessions); + + MaxConnections = istgt_get_intval(sp, "MaxConnections"); + if (MaxConnections < 1) { + MaxConnections = DEFAULT_MAX_CONNECTIONS; + } + istgt->MaxConnections = MaxConnections; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxConnections %d\n", + istgt->MaxConnections); + + /* Set number of luworker threads from DEFAULT_CONF */ + if (g_num_luworkers == 0) { + g_num_luworkers = istgt_get_intval(sp, "Luworkers"); + if (g_num_luworkers < 1 ||g_num_luworkers > (ISTGT_MAX_NUM_LUWORKERS - 1)) { + g_num_luworkers = ISTGT_NUM_LUWORKERS_DEFAULT; + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Luworkers %d\n", + g_num_luworkers); + + /* limited to 16bits - RFC3720(12.2) */ + if (MaxSessions > 0xffff) { + ISTGT_ERRLOG("over 65535 sessions are not supported\n"); + return -1; + } + if (MaxConnections > 0xffff) { + ISTGT_ERRLOG("over 65535 connections are not supported\n"); + return -1; + } + + MaxOutstandingR2T = istgt_get_intval(sp, "MaxOutstandingR2T"); + if (MaxOutstandingR2T < 1) { + MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T; + } + istgt->MaxOutstandingR2T = MaxOutstandingR2T; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n", + istgt->MaxOutstandingR2T); + + DefaultTime2Wait = istgt_get_intval(sp, "DefaultTime2Wait"); + if (DefaultTime2Wait < 0) { + DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT; + } + istgt->DefaultTime2Wait = DefaultTime2Wait; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n", + istgt->DefaultTime2Wait); + + DefaultTime2Retain = istgt_get_intval(sp, "DefaultTime2Retain"); + if (DefaultTime2Retain < 0) { + DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN; + } + istgt->DefaultTime2Retain = DefaultTime2Retain; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n", + istgt->DefaultTime2Retain); + + /* check size limit - RFC3720(12.15, 12.16, 12.17) */ + if (istgt->MaxOutstandingR2T > 65535) { + ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n", + istgt->MaxOutstandingR2T); + return -1; + } + if (istgt->DefaultTime2Wait > 3600) { + ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n", + istgt->DefaultTime2Wait); + return -1; + } + if (istgt->DefaultTime2Retain > 3600) { + ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n", + istgt->DefaultTime2Retain); + return -1; + } + + FirstBurstLength = istgt_get_intval(sp, "FirstBurstLength"); + if (FirstBurstLength < 0) { + FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH; + } + istgt->FirstBurstLength = FirstBurstLength; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n", + istgt->FirstBurstLength); + + MaxBurstLength = istgt_get_intval(sp, "MaxBurstLength"); + if (MaxBurstLength < 0) { + MaxBurstLength = DEFAULT_MAXBURSTLENGTH; + } + istgt->MaxBurstLength = MaxBurstLength; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n", + istgt->MaxBurstLength); + + MaxRecvDataSegmentLength + = istgt_get_intval(sp, "MaxRecvDataSegmentLength"); + if (MaxRecvDataSegmentLength < 0) { + MaxRecvDataSegmentLength = DEFAULT_MAXRECVDATASEGMENTLENGTH; + } + istgt->MaxRecvDataSegmentLength = MaxRecvDataSegmentLength; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n", + istgt->MaxRecvDataSegmentLength); + + /* check size limit (up to 24bits - RFC3720(12.12)) */ + if (istgt->MaxBurstLength < 512) { + ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n", + istgt->MaxBurstLength); + return -1; + } + if (istgt->FirstBurstLength < 512) { + ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n", + istgt->FirstBurstLength); + return -1; + } + if (istgt->FirstBurstLength > istgt->MaxBurstLength) { + ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n", + istgt->FirstBurstLength, istgt->MaxBurstLength); + return -1; + } + if (istgt->MaxBurstLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", + istgt->MaxBurstLength); + return -1; + } + if (istgt->MaxRecvDataSegmentLength < 512) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n", + istgt->MaxRecvDataSegmentLength); + return -1; + } + if (istgt->MaxRecvDataSegmentLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n", + istgt->MaxRecvDataSegmentLength); + return -1; + } + + val = istgt_get_val(sp, "InitialR2T"); + if (val == NULL) { + InitialR2T = DEFAULT_INITIALR2T; + } else if (strcasecmp(val, "Yes") == 0) { + InitialR2T = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + InitialR2T = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + istgt->InitialR2T = InitialR2T; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n", + istgt->InitialR2T ? "Yes" : "No"); + + val = istgt_get_val(sp, "ImmediateData"); + if (val == NULL) { + ImmediateData = DEFAULT_IMMEDIATEDATA; + } else if (strcasecmp(val, "Yes") == 0) { + ImmediateData = 1; + } else if (strcasecmp(val, "No") == 0) { + ImmediateData = 0; + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + istgt->ImmediateData = ImmediateData; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n", + istgt->ImmediateData ? "Yes" : "No"); + + val = istgt_get_val(sp, "DataPDUInOrder"); + if (val == NULL) { + DataPDUInOrder = DEFAULT_DATAPDUINORDER; + } else if (strcasecmp(val, "Yes") == 0) { + DataPDUInOrder = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + DataPDUInOrder = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + istgt->DataPDUInOrder = DataPDUInOrder; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n", + istgt->DataPDUInOrder ? "Yes" : "No"); + + val = istgt_get_val(sp, "DataSequenceInOrder"); + if (val == NULL) { + DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER; + } else if (strcasecmp(val, "Yes") == 0) { + DataSequenceInOrder = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + DataSequenceInOrder = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + istgt->DataSequenceInOrder = DataSequenceInOrder; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n", + istgt->DataSequenceInOrder ? "Yes" : "No"); + + ErrorRecoveryLevel = istgt_get_intval(sp, "ErrorRecoveryLevel"); + if (ErrorRecoveryLevel < 0) { + ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL; + } else if (ErrorRecoveryLevel == 0) { + ErrorRecoveryLevel = 0; + } else if (ErrorRecoveryLevel == 1) { +#if 0 + ErrorRecoveryLevel = 1; +#else + ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel); + return -1; +#endif + } else if (ErrorRecoveryLevel == 2) { +#if 0 + ErrorRecoveryLevel = 2; +#else + ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel); + return -1; +#endif + } else { + ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel); + return -1; + } + istgt->ErrorRecoveryLevel = ErrorRecoveryLevel; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n", + istgt->ErrorRecoveryLevel); + + timeout = istgt_get_intval(sp, "Timeout"); + if (timeout < 0) { + timeout = DEFAULT_TIMEOUT; + } + istgt->timeout = timeout; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Timeout %d\n", + istgt->timeout); + + nopininterval = istgt_get_intval(sp, "NopInInterval"); + if (nopininterval < 0) { + nopininterval = DEFAULT_NOPININTERVAL; + } + istgt->nopininterval = nopininterval; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NopInInterval %d\n", + istgt->nopininterval); + + maxr2t = istgt_get_intval(sp, "MaxR2T"); + if (maxr2t < 0) { + maxr2t = DEFAULT_MAXR2T; + } + if (maxr2t > MAX_R2T) { + ISTGT_ERRLOG("MaxR2T(%d) > %d\n", + maxr2t, MAX_R2T); + return -1; + } + istgt->maxr2t = maxr2t; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxR2T %d\n", + istgt->maxr2t); + + val = istgt_get_val(sp, "DiscoveryAuthMethod"); + if (val == NULL) { + istgt->no_discovery_auth = 0; + istgt->req_discovery_auth = 0; + istgt->req_discovery_auth_mutual = 0; + } else { + istgt->no_discovery_auth = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "DiscoveryAuthMethod", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "CHAP") == 0) { + istgt->req_discovery_auth = 1; + } else if (strcasecmp(val, "Mutual") == 0) { + istgt->req_discovery_auth_mutual = 1; + } else if (strcasecmp(val, "Auto") == 0) { + istgt->req_discovery_auth = 0; + istgt->req_discovery_auth_mutual = 0; + } else if (strcasecmp(val, "None") == 0) { + istgt->no_discovery_auth = 1; + istgt->req_discovery_auth = 0; + istgt->req_discovery_auth_mutual = 0; + } else { + ISTGT_ERRLOG("unknown auth\n"); + return -1; + } + } + if (istgt->req_discovery_auth_mutual && !istgt->req_discovery_auth) { + ISTGT_ERRLOG("Mutual but not CHAP\n"); + return -1; + } + } + if (istgt->no_discovery_auth != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "DiscoveryAuthMethod None\n"); + } else if (istgt->req_discovery_auth == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "DiscoveryAuthMethod Auto\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "DiscoveryAuthMethod %s %s\n", + istgt->req_discovery_auth ? "CHAP" : "", + istgt->req_discovery_auth_mutual ? "Mutual" : ""); + } + + val = istgt_get_val(sp, "DiscoveryAuthGroup"); + if (val == NULL) { + istgt->discovery_auth_group = 0; + } else { + ag_tag = val; + if (strcasecmp(ag_tag, "None") == 0) { + ag_tag_i = 0; + } else { + if (strncasecmp(ag_tag, "AuthGroup", + strlen("AuthGroup")) != 0 + || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) { + ISTGT_ERRLOG("auth group error\n"); + return -1; + } + if (ag_tag_i == 0) { + ISTGT_ERRLOG("invalid auth group %d\n", + ag_tag_i); + return -1; + } + } + istgt->discovery_auth_group = ag_tag_i; + } + if (istgt->discovery_auth_group == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "DiscoveryAuthGroup None\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "DiscoveryAuthGroup AuthGroup%d\n", + istgt->discovery_auth_group); + } + + rc = istgt_uctl_init(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_uctl_init() failed\n"); + return -1; + } + rc = istgt_build_uctl_portal(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_build_uctl_portal() failed\n"); + return -1; + } + rc = istgt_build_portal_group_array(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_build_portal_array() failed\n"); + return -1; + } + rc = istgt_build_initiator_group_array(istgt); + if (rc < 0) { + ISTGT_ERRLOG("build_initiator_group_array() failed\n"); + return -1; + } + + rc = pthread_attr_init(&istgt->attr); + if (rc != 0) { + ISTGT_ERRLOG("pthread_attr_init() failed\n"); + return -1; + } + rc = pthread_attr_getstacksize(&istgt->attr, &stacksize); + if (rc != 0) { + ISTGT_ERRLOG("pthread_attr_getstacksize() failed\n"); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "current thread stack = %zd\n", stacksize); + if (stacksize < ISTGT_STACKSIZE) { + stacksize = ISTGT_STACKSIZE; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "new thread stack = %zd\n", stacksize); + rc = pthread_attr_setstacksize(&istgt->attr, stacksize); + if (rc != 0) { + ISTGT_ERRLOG("pthread_attr_setstacksize() failed\n"); + return -1; + } + } + + rc = pthread_mutexattr_init(&istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutexattr_init() failed\n"); + return -1; + } +#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP); +#else + rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ERRORCHECK); +#endif + if (rc != 0) { + ISTGT_ERRLOG("mutexattr_settype() failed\n"); + return -1; + } + rc = pthread_mutex_init(&istgt->mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + rc = pthread_mutex_init(&istgt->state_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + rc = pthread_mutex_init(&istgt->reload_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + rc = pthread_cond_init(&istgt->reload_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + return -1; + } + + rc = pipe(istgt->sig_pipe); + if (rc != 0) { + ISTGT_ERRLOG("pipe() failed\n"); + istgt->sig_pipe[0] = -1; + istgt->sig_pipe[1] = -1; + return -1; + } + + /* XXX TODO: add initializer */ + + istgt_set_state(istgt, ISTGT_STATE_INITIALIZED); + + return 0; +} + +static void +istgt_shutdown(ISTGT_Ptr istgt) +{ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_shutdown\n"); + + istgt_destory_initiator_group_array(istgt); + istgt_destroy_portal_group_array(istgt); + istgt_destroy_uctl_portal(istgt); + istgt_uctl_shutdown(istgt); + istgt_remove_pidfile(istgt); + xfree(istgt->pidfile); + xfree(istgt->authfile); + xfree(istgt->logfile); +#if 0 + xfree(istgt->mediafile); + xfree(istgt->livefile); +#endif + xfree(istgt->mediadirectory); + xfree(istgt->nodebase); + + if (istgt->sig_pipe[0] != -1) + close(istgt->sig_pipe[0]); + if (istgt->sig_pipe[1] != -1) + close(istgt->sig_pipe[1]); + + (void) pthread_cond_destroy(&istgt->reload_cond); + (void) pthread_mutex_destroy(&istgt->reload_mutex); + (void) pthread_mutex_destroy(&istgt->state_mutex); + (void) pthread_mutex_destroy(&istgt->mutex); + (void) pthread_attr_destroy(&istgt->attr); +} + +static int +istgt_pg_exist_num(CONFIG *config, int num) +{ + CF_SECTION *sp; + + sp = config->section; + while (sp != NULL) { + if (sp->type == ST_PORTALGROUP) { + if (sp->num == num) { + return 1; + } + } + sp = sp->next; + } + return -1; +} + +static PORTAL_GROUP * +istgt_get_tag_portal(ISTGT_Ptr istgt, int tag) +{ + int i; + + if (tag == 0) + return NULL; + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag == tag) { + MTX_UNLOCK(&istgt->mutex); + return &istgt->portal_group[i]; + } + } + MTX_UNLOCK(&istgt->mutex); + return NULL; +} + +#if 0 +static int +istgt_get_num_of_portals(CF_SECTION *sp) +{ + char *label, *portal; + int portals; + int rc; + int i; + + for (i = 0; ; i++) { + label = istgt_get_nmval(sp, "Portal", i, 0); + portal = istgt_get_nmval(sp, "Portal", i, 1); + if (label == NULL || portal == NULL) + break; + rc = istgt_parse_portal(portal, NULL, NULL); + if (rc < 0) { + ISTGT_ERRLOG("parse portal error (%s)\n", portal); + return -1; + } + } + portals = i; + if (portals > MAX_PORTAL) { + ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals); + return -1; + } + return portals; +} +#endif + +#define RELOAD_CMD_LENGTH 5 +static int +istgt_pg_reload_delete(ISTGT_Ptr istgt) +{ + char tmp[RELOAD_CMD_LENGTH]; + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_delete\n"); + + istgt->pg_reload = 0; + /* request delete */ + tmp[0] = 'D'; + DSET32(&tmp[1], 0); + rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH); + if (rc < 0 || rc != RELOAD_CMD_LENGTH) { + ISTGT_ERRLOG("write() failed\n"); + return -1; + } + /* wait for completion */ + MTX_LOCK(&istgt->reload_mutex); + while (istgt->pg_reload == 0) { + pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex); + } + rc = istgt->pg_reload; + MTX_UNLOCK(&istgt->reload_mutex); + if (rc < 0) { + if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) { + ISTGT_WARNLOG("%s\n", "pg_reload abort"); + return -1; + } + } + return 0; +} + +static int +istgt_pg_reload_update(ISTGT_Ptr istgt) +{ + char tmp[RELOAD_CMD_LENGTH]; + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_update\n"); + + istgt->pg_reload = 0; + /* request update */ + tmp[0] = 'U'; + DSET32(&tmp[1], 0); + rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH); + if (rc < 0 || rc != RELOAD_CMD_LENGTH) { + ISTGT_ERRLOG("write() failed\n"); + return -1; + } + /* wait for completion */ + MTX_LOCK(&istgt->reload_mutex); + while (istgt->pg_reload == 0) { + pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex); + } + rc = istgt->pg_reload; + MTX_UNLOCK(&istgt->reload_mutex); + if (rc < 0) { + if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) { + ISTGT_WARNLOG("%s\n", "pg_reload abort"); + return -1; + } + } + return 0; +} + +static int +istgt_ig_exist_num(CONFIG *config, int num) +{ + CF_SECTION *sp; + + sp = config->section; + while (sp != NULL) { + if (sp->type == ST_INITIATORGROUP) { + if (sp->num == num) { + return 1; + } + } + sp = sp->next; + } + return -1; +} + +static int +istgt_ig_reload_delete(ISTGT_Ptr istgt) +{ + INITIATOR_GROUP *igp; + int rc; + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_delete\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->ninitiator_group; i++) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload idx=%d, (%d)\n", + i, istgt->ninitiator_group); + igp = &istgt->initiator_group[i]; + rc = istgt_ig_exist_num(istgt->config, igp->tag); + if (rc < 0) { + if (igp->ref != 0) { + ISTGT_ERRLOG("delete request for referenced IG%d\n", + igp->tag); + } else { + ISTGT_NOTICELOG("delete IG%d\n", igp->tag); + /* free old IG */ + for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) { + xfree(istgt->initiator_group[i].initiators[j]); + } + xfree(istgt->initiator_group[i].initiators); + for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) { + xfree(istgt->initiator_group[i].netmasks[j]); + } + xfree(istgt->initiator_group[i].netmasks); + + /* move from beyond the IG */ + for (j = i; j < istgt->ninitiator_group - 1; j++) { + istgt->initiator_group[j].ninitiators + = istgt->initiator_group[j+1].ninitiators; + istgt->initiator_group[j].initiators + = istgt->initiator_group[j+1].initiators; + istgt->initiator_group[j].nnetmasks + = istgt->initiator_group[j+1].nnetmasks; + istgt->initiator_group[j].netmasks + = istgt->initiator_group[j+1].netmasks; + istgt->initiator_group[j].ref + = istgt->initiator_group[j+1].ref; + istgt->initiator_group[j].idx + = istgt->initiator_group[j+1].idx; + istgt->initiator_group[j].tag + = istgt->initiator_group[j+1].tag; + } + istgt->ninitiator_group--; + } + } + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_ig_reload_update(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_update\n"); + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_INITIATORGROUP) { + if (sp->num == 0) { + ISTGT_ERRLOG("Group 0 is invalid\n"); + goto skip_ig; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload tag=%d\n", sp->num); +#if 0 + rc = istgt_ig_exist_num(istgt->config_old, sp->num); +#else + rc = -1; + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->ninitiator_group; i++) { + if (istgt->initiator_group[i].tag == sp->num) { + rc = 1; + break; + } + } + MTX_UNLOCK(&istgt->mutex); +#endif + if (rc < 0) { + rc = istgt_add_initiator_group(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("add_initiator_group() failed\n"); + goto skip_ig; + } + ISTGT_NOTICELOG("add IG%d\n", sp->num); + } else { + rc = istgt_update_initiator_group(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("update_initiator_group() failed\n"); + goto skip_ig; + } else if (rc == 0) { + // not modified + } else if (rc > 0) { + ISTGT_NOTICELOG("update IG%d\n", sp->num); + } + } + } + skip_ig: + sp = sp->next; + } + return 0; +} + +int istgtversn = 0; +char istgtvers[80]; + + +int +istgt_reload(ISTGT_Ptr istgt) +{ + CONFIG *config_new, *config_old; + char *config_file; + int rc; + uint32_t gen; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_reload\n"); + /* prepare config structure */ + config_new = istgt_allocate_config(); + config_old = istgt->config; + config_file = config_old->file; + rc = istgt_read_config(config_new, config_file); + if (rc < 0) { + ISTGT_ERRLOG("config error\n"); + return -1; + } + if (config_new->section == NULL) { + ISTGT_ERRLOG("empty config\n"); + istgt_free_config(config_new); + return -1; + } + istgt->config = config_new; + istgt->config_old = config_old; + gen = ++istgt->generation; + + /* reload sub groups */ + ISTGT_NOTICELOG("reload configuration#%u start [%s]\n", gen, istgtvers); + rc = istgt_lu_reload_delete(istgt); + if (rc < 0) { + ISTGT_ERRLOG("LU reload del error\n"); + return -1; + } + rc = istgt_ig_reload_delete(istgt); + if (rc < 0) { + ISTGT_ERRLOG("IG reload del error\n"); + return -1; + } + rc = istgt_pg_reload_delete(istgt); + if (rc < 0) { + ISTGT_ERRLOG("PG reload del error\n"); + return -1; + } + + rc = istgt_pg_reload_update(istgt); + if (rc < 0) { + ISTGT_ERRLOG("PG reload add error\n"); + return -1; + } + rc = istgt_ig_reload_update(istgt); + if (rc < 0) { + ISTGT_ERRLOG("IG reload add error\n"); + return -1; + } + rc = istgt_lu_reload_update(istgt); + if (rc < 0) { + ISTGT_ERRLOG("LU reload add error\n"); + return -1; + } + + istgt->config_old = NULL; + istgt_free_config(config_old); + ISTGT_NOTICELOG("reload configuration#%"PRIu32" end [%s]\n", gen, istgtvers); + return 0; +} + +static PORTAL * +istgt_get_sock_portal(ISTGT_Ptr istgt, int sock) +{ + int i, j; + + if (sock < 0) + return NULL; + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + for (j = 0; j < istgt->portal_group[i].nportals; j++) { + if (istgt->portal_group[i].portals[j]->sock == sock) { + MTX_UNLOCK(&istgt->mutex); + return istgt->portal_group[i].portals[j]; + } + } + } + MTX_UNLOCK(&istgt->mutex); + return NULL; +} + +static int +istgt_pg_delete(ISTGT_Ptr istgt) +{ + PORTAL_GROUP *pgp; + int rc; + int i; + + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + pgp = &istgt->portal_group[i]; + if (pgp->tag == 0) + continue; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload idx=%d, tag=%d, (%d)\n", + i, pgp->tag, istgt->nportal_group); + rc = istgt_pg_exist_num(istgt->config, pgp->tag); + if (rc < 0) { + if (pgp->ref != 0) { + ISTGT_ERRLOG("delete request for referenced PG%d\n", + pgp->tag); + } else { + ISTGT_NOTICELOG("delete PG%d\n", pgp->tag); + pgp->tag = 0; + (void) istgt_close_portal_group(pgp); + } + } + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_pg_update(ISTGT_Ptr istgt) +{ + PORTAL_GROUP *pgp; + CF_SECTION *sp; + int pgp_idx; + int rc; + int i; + + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_PORTALGROUP) { + if (sp->num == 0) { + ISTGT_ERRLOG("Group 0 is invalid\n"); + goto skip_pg; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload tag=%d\n", sp->num); +#if 0 + rc = istgt_pg_exist_num(istgt->config_old, sp->num); +#else + rc = -1; + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag == sp->num) { + rc = 1; + break; + } + } + MTX_UNLOCK(&istgt->mutex); +#endif + if (rc < 0) { + rc = istgt_add_portal_group(istgt, sp, &pgp_idx); + if (rc < 0) { + ISTGT_ERRLOG("add_portal_group() failed\n"); + goto skip_pg; + } + MTX_LOCK(&istgt->mutex); + pgp = &istgt->portal_group[pgp_idx]; + (void) istgt_open_portal_group(pgp); + MTX_UNLOCK(&istgt->mutex); + ISTGT_NOTICELOG("add PG%d\n", sp->num); + } else { + //portals = istgt_get_num_of_portals(sp); + pgp = istgt_get_tag_portal(istgt, sp->num); + if (istgt_pg_match_all(pgp, sp)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "skip for PG%d\n", sp->num); + } else if (pgp->ref != 0) { + ISTGT_ERRLOG("update request for referenced PG%d\n", + pgp->tag); + } else { + /* delete old sock */ + MTX_LOCK(&istgt->mutex); + pgp_idx = pgp->idx; + (void) istgt_close_portal_group(pgp); + MTX_UNLOCK(&istgt->mutex); + rc = istgt_update_portal_group(istgt, sp, &pgp_idx); + if (rc < 0) { + ISTGT_ERRLOG("update_portal_group() failed\n"); + goto skip_pg; + } else if (rc == 0) { + // not modified + } else if (rc > 0) { + /* add new sock */ + MTX_LOCK(&istgt->mutex); + pgp = &istgt->portal_group[pgp_idx]; + (void) istgt_open_portal_group(pgp); + MTX_UNLOCK(&istgt->mutex); + ISTGT_NOTICELOG("update PG%d\n", sp->num); + } + } + } + } + skip_pg: + sp = sp->next; + } + return 0; +} + +static int +istgt_acceptor(ISTGT_Ptr istgt) +{ + PORTAL *pp; + int kq; + struct kevent kev; + struct timespec kev_timeout; + int kqsocks[MAX_PORTAL_GROUP + MAX_UCPORTAL]; + struct sockaddr_storage sa; + socklen_t salen; + int sock; + int rc, n; + int ucidx; + int nidx; + int i, j; + + if (istgt_get_state(istgt) != ISTGT_STATE_INITIALIZED) { + ISTGT_ERRLOG("not initialized\n"); + return -1; + } + /* now running main thread */ + istgt_set_state(istgt, ISTGT_STATE_RUNNING); + +reload: + nidx = 0; + kq = kqueue(); + if (kq == -1) { + ISTGT_ERRLOG("kqueue() failed\n"); + return -1; + } + for (i = 0; i < (int)(sizeof kqsocks / sizeof *kqsocks); i++) { + kqsocks[i] = -1; + } + MTX_LOCK(&istgt->mutex); + for (i = 0; i < istgt->nportal_group; i++) { + for (j = 0; j < istgt->portal_group[i].nportals; j++) { + if (istgt->portal_group[i].portals[j]->sock >= 0) { + ISTGT_EV_SET(&kev, istgt->portal_group[i].portals[j]->sock, + EVFILT_READ, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return -1; + } + kqsocks[nidx] = istgt->portal_group[i].portals[j]->sock; + nidx++; + } + } + } + MTX_UNLOCK(&istgt->mutex); + ucidx = nidx; + for (i = 0; i < istgt->nuctl_portal; i++) { + ISTGT_EV_SET(&kev, istgt->uctl_portal[i].sock, + EVFILT_READ, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return -1; + } + kqsocks[nidx] = istgt->uctl_portal[i].sock; + nidx++; + } + ISTGT_EV_SET(&kev, istgt->sig_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return -1; + } + kqsocks[nidx] = istgt->sig_pipe[0]; + nidx++; + +// signal(SIGTERM, SIG_IGN); +// signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); +// if (!istgt->daemon) + { + ISTGT_EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return -1; + } + ISTGT_EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return -1; + } + } + + while (1) { + if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) { + break; + } + //ISTGT_TRACELOG(ISTGT_TRACE_NET, "kevent %d\n", nidx); + kev_timeout.tv_sec = 10; + kev_timeout.tv_nsec = 0; + rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout); + if (rc == -1 && errno == EINTR) { + continue; + } + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + break; + } + if (rc == 0) { + /* idle timeout */ + //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent TIMEOUT\n"); + continue; + } + if (kev.filter == EVFILT_SIGNAL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n"); + if (kev.ident == SIGINT || kev.ident == SIGTERM) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "kevent SIGNAL SIGINT/SIGTERM\n"); + break; + } + continue; + } + + n = rc; + for (i = 0; n != 0 && i < ucidx; i++) { + if (kev.ident == (uintptr_t)kqsocks[i]) { + if (kev.flags) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "flags %x\n", + kev.flags); + } + n--; + memset(&sa, 0, sizeof(sa)); + salen = sizeof(sa); + ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %ld\n", + (unsigned long)kev.ident); + pp = istgt_get_sock_portal(istgt, kev.ident); + rc = accept(kev.ident, (struct sockaddr *) &sa, &salen); + if (rc < 0) { + ISTGT_ERRLOG("accept error errno:%d rc:%d\n", errno, rc); + continue; + } + sock = rc; + rc = istgt_create_conn(istgt, pp, sock, + (struct sockaddr *) &sa, salen); + if (rc < 0) { + close(sock); + ISTGT_ERRLOG("istgt_create_conn() failed\n"); + continue; + } + } + } + + /* check for control */ + for (i = 0; n != 0 && i < istgt->nuctl_portal; i++) { + if (kev.ident == (uintptr_t)istgt->uctl_portal[i].sock) { + if (kev.flags) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "flags %x\n", + kev.flags); + } + n--; + memset(&sa, 0, sizeof(sa)); + salen = sizeof(sa); + ISTGT_TRACELOG(ISTGT_TRACE_NET, + "accept %ld\n", (unsigned long)kev.ident); + rc = accept(kev.ident, + (struct sockaddr *) &sa, &salen); + if (rc < 0) { + ISTGT_ERRLOG("accept error errno:%d rc:%d\n", errno, rc); + continue; + } + sock = rc; + rc = istgt_create_uctl(istgt, + &istgt->uctl_portal[i], sock, + (struct sockaddr *) &sa, salen); + if (rc < 0) { + close(sock); + ISTGT_ERRLOG("istgt_create_uctl() failed\n"); + continue; + } + } + } + + /* check for signal thread */ + if (kev.ident == (uintptr_t)istgt->sig_pipe[0]) { + + if (kev.flags & (EV_EOF|EV_ERROR)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "kevent EOF/ERROR\n"); + break; + } + char tmp[RELOAD_CMD_LENGTH]; + //int pgp_idx; + int rc2; + + rc = read(istgt->sig_pipe[0], tmp, RELOAD_CMD_LENGTH); + if (rc < 0 || rc == 0 || rc != RELOAD_CMD_LENGTH) { + ISTGT_ERRLOG("read() failed\n"); + break; + } + //pgp_idx = (int)DGET32(&tmp[1]); + + if (tmp[0] == 'E') { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "exit request (main loop)\n"); + break; + } + if (tmp[0] == 'D') { + rc = istgt_pg_delete(istgt); + MTX_LOCK(&istgt->reload_mutex); + istgt->pg_reload = rc < 0 ? -1 : 1; + rc2 = pthread_cond_broadcast(&istgt->reload_cond); + if (rc2 != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + } + MTX_UNLOCK(&istgt->reload_mutex); + if (rc < 0) { + ISTGT_ERRLOG("pg_delete() failed\n"); + //break; + } + } + if (tmp[0] == 'U') { + rc = istgt_pg_update(istgt); + MTX_LOCK(&istgt->reload_mutex); + istgt->pg_reload = rc < 0 ? -1 : 1; + rc2 = pthread_cond_broadcast(&istgt->reload_cond); + if (rc2 != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + } + MTX_UNLOCK(&istgt->reload_mutex); + if (rc < 0) { + ISTGT_ERRLOG("pg_update() failed\n"); + //break; + } + } + close(kq); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "reload accept loop\n"); + goto reload; + } + } + close(kq); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n"); + istgt_set_state(istgt, ISTGT_STATE_EXITING); + istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING); + + return 0; +} + +static void +usage(void) +{ + printf("istgt [options]\n"); + printf("options:\n"); + printf(" -c config config file (default %s)\n", DEFAULT_CONFIG); + printf(" -p pidfile use specific file\n"); + printf(" -l facility use specific syslog facility (default %s)\n", + DEFAULT_LOG_FACILITY); + printf(" -m mode operational mode (default %d, 0=traditional, " + "1=normal, 2=experimental)\n", DEFAULT_ISTGT_SWMODE); + printf(" -t flag trace flag (all, net, iscsi, scsi, lu)\n"); + printf(" -q quiet warnings\n"); + printf(" -D don't detach from tty\n"); + printf(" -H show this usage\n"); + printf(" -V show version\n"); + printf(" -P Persist Disabled\n"); +} + +#if 0 +int unmap_support_global = 0; +static void +get_zvol_unmap_enabled(void) +{ + uint64_t unmap_val = 0; + size_t size = sizeof(unmap_val); + if (sysctlbyname("vfs.zfs.zvol_unmap_enabled", &unmap_val, &size, NULL, 0) == 0 + && unmap_val != 0) + unmap_support = 1; + else + unmap_support = 0; + unmap_support_global = unmap_support; +} + +int is_unmap_enabled(void) +{ + return unmap_support; +} + #endif + +static int persist = 1; +int is_persist_enabled(void) +{ + return persist; +} + +clockid_t clockid = CLOCK_UPTIME_FAST; // CLOCK_SECOND CLOCK_MONOTONIC_FAST +extern int detectDoubleFree; +//int enable_xcopy = 0; +int enable_oldBL = 0; + +void *timerfn(void *ptr __attribute__((__unused__))) +{ + ISTGT_QUEUE backupconns; + istgt_queue_init(&backupconns); + CONN *conn; + while(1) + { + while((conn = (CONN *)(istgt_queue_dequeue(&closedconns))) != NULL) + { + if(((time(NULL) - conn->closetime) > 300) && (conn->inflight == 0)) + istgt_free_conn(conn); + else + istgt_queue_enqueue(&backupconns, conn); + } + while((conn = (CONN *)(istgt_queue_dequeue(&backupconns))) != NULL) + istgt_queue_enqueue(&closedconns, conn); + sleep(60); + } + return (void *)NULL; +} +void *zv; +void *spa; +int +main(int argc, char **argv) +{ + ISTGT_Ptr istgt; + const char *config_file = DEFAULT_CONFIG; + const char *pidfile = NULL; + const char *logfacility = NULL; + const char *logpriority = NULL; + CONFIG *config; + #if 0 + pthread_t sigthread; + struct sigaction sigact, sigoldact_pipe, sigoldact_int, sigoldact_term; + struct sigaction sigoldact_hup, sigoldact_info; + struct sigaction sigoldact_wakeup, sigoldact_io; + sigset_t signew, sigold; + int retry = 10; + #endif + pthread_t timerthread; + int detach = 1; + int swmode; + int ch; + int rc; + + send_abrt_resp = 0; + abort_result_queue = 0; + wait_inflights = 1; + clear_resv = 1; + + if (sizeof (ISCSI_BHS) != ISCSI_BHS_LEN) { + fprintf(stderr, "Internal Error\n"); + exit(EXIT_FAILURE); + } + + detectDoubleFree = 0; + memset(&g_istgt, 0, sizeof g_istgt); + istgt = &g_istgt; + istgt->state = ISTGT_STATE_INVALID; + istgt->swmode = DEFAULT_ISTGT_SWMODE; + istgt->sig_pipe[0] = istgt->sig_pipe[1] = -1; + istgt->daemon = 0; + istgt->generation = 0; + + g_num_luworkers = 0; + + istgtversn = snprintf(istgtvers, 79, "istgt:%s.%s:%s:%s", ISTGT_VERSION, ISTGT_EXTRA_VERSION, __TIME__, __DATE__); + istgtvers[79] = '\0'; + + pthread_t slf = pthread_self(); + snprintf(tinfo, sizeof tinfo, "m#%d.%d", (int)(((uint64_t *)slf)[0]), getpid()); +#ifdef HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(pthread_self(), tinfo); +#endif + + while ((ch = getopt(argc, argv, "c:p:l:m:t:N:qDHVFOP")) != -1) { + switch (ch) { + case 'c': + config_file = optarg; + break; + case 'p': + pidfile = optarg; + break; + case 'l': + logfacility = optarg; + break; + case 'm': + swmode = strtol(optarg, NULL, 10); + if (swmode == ISTGT_SWMODE_TRADITIONAL + || swmode == ISTGT_SWMODE_NORMAL + || swmode == ISTGT_SWMODE_EXPERIMENTAL) { + istgt->swmode = swmode; + } else { + fprintf(stderr, "unknown mode %x\n", swmode); + usage(); + exit(EXIT_FAILURE); + } + break; + case 't': + if (strcasecmp(optarg, "NET") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_NET); + } else if (strcasecmp(optarg, "ISCSI") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_ISCSI); + } else if (strcasecmp(optarg, "SCSI") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_SCSI); + } else if (strcasecmp(optarg, "LU") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_LU); + } else if (strcasecmp(optarg, "PQ") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_PQ); + } else if (strcasecmp(optarg, "MEM") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_MEM); + } else if (strcasecmp(optarg, "PROF") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_PROF); + } else if (strcasecmp(optarg, "PROFX") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_PROFX); + } else if (strcasecmp(optarg, "CMD") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_CMD); + } else if (strcasecmp(optarg, "ALL") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_ALL); + } else if (strcasecmp(optarg, "NONE") == 0) { + istgt_set_trace_flag(ISTGT_TRACE_NONE); + } else { + fprintf(stderr, "unknown flag\n"); + usage(); + exit(EXIT_FAILURE); + } + break; + case 'q': + g_warn_flag = 0; + break; + /* + * CloudByte ES1.1 - added option for spawning more than one + * luworker thread for a lun + * This could probably be moved to the conf file but for now + * spawning this from cmd line seems safer as istgt can easily + * be restarted on the go and importantly, didn't want to + * diverge from the mainline/std conf file semantics + */ + case 'N': + g_num_luworkers = strtol(optarg, NULL, 10); + if ((g_num_luworkers > (ISTGT_MAX_NUM_LUWORKERS - 1)) || (g_num_luworkers <= 0)) { + g_num_luworkers = 0; + fprintf(stderr, "Incorrect number of lu worker threads specified\n" ); + usage(); + exit(EXIT_FAILURE); + } + break; + case 'D': + detach = 0; + break; + case 'F': + detectDoubleFree = 1; + break; + case 'O': + enable_oldBL = 1; + break; + case 'V': + printf("istgt version %s %s\n", ISTGT_VERSION, istgtvers); + printf("istgt extra version %s\n", ISTGT_EXTRA_VERSION); + exit(EXIT_SUCCESS); + case 'P': + persist = 0; + break; + case 'H': + default: + usage(); + exit(EXIT_SUCCESS); + } + } + + ISTGT_NOTICELOG("%s: starting\n", istgtvers); + poolinit(); + /* read config files */ + config = istgt_allocate_config(); + rc = istgt_read_config(config, config_file); + if (rc < 0) { + fprintf(stderr, "config error\n"); + poolfini(); + exit(EXIT_FAILURE); + } + if (config->section == NULL) { + fprintf(stderr, "empty config\n"); + istgt_free_config(config); + poolfini(); + exit(EXIT_FAILURE); + } + istgt->config = config; + istgt->config_old = NULL; + //istgt_print_config(config); + + + /* open log files */ + if (logfacility == NULL) { + logfacility = istgt_get_log_facility(config); + } + rc = istgt_set_log_facility(logfacility); + if (rc < 0) { + fprintf(stderr, "log facility error\n"); + istgt_free_config(config); + exit(EXIT_FAILURE); + } + if (logpriority == NULL) { + logpriority = DEFAULT_LOG_PRIORITY; + } + rc = istgt_set_log_priority(logpriority); + if (rc < 0) { + fprintf(stderr, "log priority error\n"); + istgt_free_config(config); + exit(EXIT_FAILURE); + } + istgt_open_log(); + + ISTGT_NOTICELOG("%s read config mode:%d %s", istgtvers, + istgt->swmode, +#ifdef USE_ATOMIC + "host-atomic" +#elif defined (USE_GCC_ATOMIC) + "gcc-atomic" +#else + "gen-atomic" +#endif /* USE_ATOMIC */ + ); + +#ifdef ISTGT_USE_CRC32C_TABLE + /* build crc32c table */ + istgt_init_crc32c_table(); +#endif /* ISTGT_USE_CRC32C_TABLE */ + + /* initialize sub modules */ + rc = istgt_init(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_init() failed\n"); + initialize_error: + istgt_close_log(); + istgt_free_config(config); + poolfini(); + exit(EXIT_FAILURE); + } + rc = istgt_lu_init(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_lu_init() failed\n"); + goto initialize_error; + } + rc = istgt_iscsi_init(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_iscsi_init() failed\n"); + goto initialize_error; + } + + /* override by command line */ + if (pidfile != NULL) { + xfree(istgt->pidfile); + istgt->pidfile = xstrdup(pidfile); + } + + /* detach from tty and run background */ + fflush(stdout); + if (detach) { + istgt->daemon = 1; + rc = daemon(0, 0); + if (rc < 0) { + ISTGT_ERRLOG("daemon() failed\n"); + goto initialize_error; + } + } + + /* setup signal handler thread */ + signal(SIGPIPE, SIG_IGN); + #if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "setup signal handler\n"); + memset(&sigact, 0, sizeof sigact); + memset(&sigoldact_pipe, 0, sizeof sigoldact_pipe); + memset(&sigoldact_int, 0, sizeof sigoldact_int); + memset(&sigoldact_term, 0, sizeof sigoldact_term); + memset(&sigoldact_hup, 0, sizeof sigoldact_hup); + memset(&sigoldact_info, 0, sizeof sigoldact_info); + memset(&sigoldact_wakeup, 0, sizeof sigoldact_wakeup); + memset(&sigoldact_io, 0, sizeof sigoldact_io); + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGPIPE, &sigact, &sigoldact_pipe); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGPIPE) failed\n"); + goto initialize_error; + } + sigact.sa_handler = istgt_sigint; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGINT, &sigact, &sigoldact_int); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGINT) failed\n"); + goto initialize_error; + } + sigact.sa_handler = istgt_sigterm; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGTERM, &sigact, &sigoldact_term); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGTERM) failed\n"); + goto initialize_error; + } + sigact.sa_handler = istgt_sighup; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGHUP, &sigact, &sigoldact_hup); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGHUP) failed\n"); + goto initialize_error; + } +#ifdef SIGINFO + sigact.sa_handler = istgt_siginfo; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGINFO, &sigact, &sigoldact_info); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGINFO) failed\n"); + goto initialize_error; + } +#endif +#ifdef ISTGT_USE_SIGRT + if (ISTGT_SIGWAKEUP < SIGRTMIN + || ISTGT_SIGWAKEUP > SIGRTMAX) { + ISTGT_ERRLOG("SIGRT error\n"); + goto initialize_error; + } +#endif /* ISTGT_USE_SIGRT */ + sigact.sa_handler = istgt_sigwakeup; + sigemptyset(&sigact.sa_mask); + rc = sigaction(ISTGT_SIGWAKEUP, &sigact, &sigoldact_wakeup); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(ISTGT_SIGWAKEUP) failed\n"); + goto initialize_error; + } +#ifdef SIGIO + sigact.sa_handler = istgt_sigio; + sigemptyset(&sigact.sa_mask); + rc = sigaction(SIGIO, &sigact, &sigoldact_io); + if (rc < 0) { + ISTGT_ERRLOG("sigaction(SIGIO) failed\n"); + goto initialize_error; + } +#endif + pthread_sigmask(SIG_SETMASK, NULL, &signew); + sigaddset(&signew, SIGINT); + sigaddset(&signew, SIGTERM); + sigaddset(&signew, SIGQUIT); + sigaddset(&signew, SIGHUP); +#ifdef SIGINFO + sigaddset(&signew, SIGINFO); +#endif + sigaddset(&signew, SIGUSR1); + sigaddset(&signew, SIGUSR2); +#ifdef SIGIO + sigaddset(&signew, SIGIO); +#endif + sigaddset(&signew, ISTGT_SIGWAKEUP); + pthread_sigmask(SIG_SETMASK, &signew, &sigold); +#ifdef ISTGT_STACKSIZE + rc = pthread_create(&sigthread, &istgt->attr, &istgt_sighandler, + (void *) istgt); +#else + rc = pthread_create(&sigthread, NULL, &istgt_sighandler, + (void *) istgt); +#endif + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed\n"); + goto initialize_error; + } +#if 0 + rc = pthread_detach(sigthread); + if (rc != 0) { + ISTGT_ERRLOG("pthread_detach() failed\n"); + goto initialize_error; + } +#endif + #endif + + /* create LUN threads for command queuing */ + istgt_queue_init(&closedconns); + rc = pthread_create(&timerthread, &istgt->attr, &timerfn, + (void *)NULL); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create(timerthread) failed\n"); + goto initialize_error; + } + + rc = istgt_lu_create_threads(istgt); + if (rc < 0) { + ISTGT_ERRLOG("lu_create_threads() failed\n"); + goto initialize_error; + } + rc = istgt_lu_set_all_state(istgt, ISTGT_STATE_RUNNING); + if (rc < 0) { + ISTGT_ERRLOG("lu_set_all_state() failed\n"); + goto initialize_error; + } + + /* open portals */ + rc = istgt_open_all_portals(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_open_all_portals() failed\n"); + goto initialize_error; + } + rc = istgt_open_uctl_portal(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_open_uctl_portal() failed\n"); + goto initialize_error; + } + + /* write pid */ + rc = istgt_write_pidfile(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_write_pid() failed\n"); + goto initialize_error; + } + + /* accept loop */ + rc = istgt_acceptor(istgt); + if (rc < 0) { + ISTGT_ERRLOG("istgt_acceptor() failed:%d\n", rc); + istgt_close_all_portals(istgt); + istgt_close_uctl_portal(istgt); + istgt_iscsi_shutdown(istgt); + istgt_lu_shutdown(istgt); + istgt_shutdown(istgt); + istgt_close_log(); + config = istgt->config; + istgt->config = NULL; + istgt_free_config(config); + poolfini(); + exit(EXIT_FAILURE); + } + + /* wait threads */ + istgt_stop_conns(); +#if 0 + while (retry > 0) { + if (istgt_get_active_conns() == 0) { + break; + } + sleep(1); + retry--; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "retry=%d\n", retry); +#endif + + ISTGT_NOTICELOG("%s exiting", istgtvers); + + /* stop signal thread */ + #if 0 + rc = pthread_join(sigthread, NULL); + if (rc != 0) { + ISTGT_ERRLOG("pthread_join() failed\n"); + poolfini(); + exit (EXIT_FAILURE); + } + #endif + + /* cleanup */ + istgt_close_all_portals(istgt); + istgt_close_uctl_portal(istgt); + istgt_iscsi_shutdown(istgt); + istgt_lu_shutdown(istgt); + istgt_shutdown(istgt); + istgt_close_log(); + config = istgt->config; + istgt->config = NULL; + istgt_free_config(config); + istgt->state = ISTGT_STATE_SHUTDOWN; + poolfini(); + return 0; +} diff --git a/src/istgt.conf b/src/istgt.conf new file mode 100644 index 00000000..7d67295a --- /dev/null +++ b/src/istgt.conf @@ -0,0 +1,62 @@ +# Global section +[Global] + NodeBase "iqn.2017-08.OpenEBS.cstor" + PidFile "/var/run/istgt.pid" + AuthFile "/usr/local/etc/istgt/auth.conf" + LogFile "/usr/local/etc/istgt/logfile" + Luworkers 1 + MediaDirectory "/mnt" + Timeout 60 + NopInInterval 20 + MaxR2T 16 + DiscoveryAuthMethod None + DiscoveryAuthGroup None + MaxSessions 32 + MaxConnections 4 + FirstBurstLength 262144 + MaxBurstLength 1048576 + MaxRecvDataSegmentLength 262144 + MaxOutstandingR2T 16 + DefaultTime2Wait 2 + DefaultTime2Retain 20 + OperationalMode 0 +# UnitControl section +[UnitControl] + AuthMethod None + AuthGroup None + Portal UC1 localhost:3261 + Netmask localhost/8 +# PortalGroup section +[PortalGroup1] + Portal DA1 localhost:3260 + +# InitiatorGroup section +[InitiatorGroup1] + InitiatorName "ALL" + Netmask "ALL" + +[InitiatorGroup2] + InitiatorName "None" + Netmask "None" + +# LogicalUnit section +[LogicalUnit2] + TargetName vol1 + TargetAlias nicknamefor-vol1 + Mapping PortalGroup1 InitiatorGroup1 + AuthMethod None + AuthGroup None + UseDigest Auto + ReadOnly No + UnitType Disk + UnitOnline Yes + BlockLength 512 + QueueDepth 32 + Luworkers 1 + UnitInquiry "CloudByte" "iscsi" "0" "4059aab98f093c5d95207f7af09d1413" + PhysRecordLength 4096 + LUN0 Storage /home/payes/vol1 1G 32k + LUN0 Option Unmap Disable + LUN0 Option WZero Disable + LUN0 Option ATS Disable + LUN0 Option XCOPY Disable diff --git a/src/istgt.h b/src/istgt.h new file mode 100644 index 00000000..1131fc0e --- /dev/null +++ b/src/istgt.h @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_H +#define ISTGT_H +#define CLOCK_UPTIME_FAST 8 +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __FreeBSD__ +#ifdef USE_ATOMIC +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MACHINE_ATOMIC_H +#include +#endif +#ifdef HAVE_SYS_ATOMIC_H +#include +#endif +#endif /* USE_ATOMIC */ +#endif + +#include "build.h" + +#include +#include +#include "istgt_log.h" +#include "istgt_conf.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define ISTGT_GNUC_PREREQ(ma,mi) \ + (__GNUC__ > (ma) || (__GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))) +#else +#define ISTGT_GNUC_PREREQ(ma,mi) 0 +#endif + +#define MAX_TMPBUF 1024 +#define MAX_ADDRBUF 64 +#define MAX_INITIATOR_ADDR (MAX_ADDRBUF) +#define MAX_INITIATOR_NAME 256 +#define MAX_TARGET_ADDR (MAX_ADDRBUF) +#define MAX_TARGET_NAME 256 +#define MAX_ISCSI_NAME 256 + +#define MAX_UCPORTAL 16 +#define MAX_PORTAL 1024 +#define MAX_INITIATOR 256 +#define MAX_NETMASK 256 +#define MAX_PORTAL_GROUP 4096 +#define MAX_INITIATOR_GROUP 4096 +#define MAX_LOGICAL_UNIT 4096 +#define MAX_R2T 256 + +#define DEFAULT_CONFIG BUILD_ETC_ISTGT "/istgt.conf" +#define DEFAULT_PIDFILE "/var/run/istgt.pid" +#define DEFAULT_AUTHFILE BUILD_ETC_ISTGT "/auth.conf" +#define DEFAULT_LOG_FILE BUILD_ETC_ISTGT "/logfile" +#define DEFAULT_OPERATIONAL_MODE 0 /* Normal mode of operation */ +#if 0 +#define DEFAULT_MEDIAFILE BUILD_ETC_ISTGT "/media.conf" +#define DEFAULT_LIVEFILE BUILD_ETC_ISTGT "/istgt.live" +#endif +#define DEFAULT_MEDIADIRECTORY BUILD_VAR_ISTGT +#define DEFAULT_NODEBASE "iqn.2007-09.jp.ne.peach.istgt" +#define DEFAULT_PORT 3260 +#define DEFAULT_MAX_SESSIONS 32 +#define DEFAULT_MAX_CONNECTIONS 4 +#define DEFAULT_MAXOUTSTANDINGR2T 16 +#define DEFAULT_DEFAULTTIME2WAIT 2 +#define DEFAULT_DEFAULTTIME2RETAIN 20 +#define DEFAULT_FIRSTBURSTLENGTH 65536 +#define DEFAULT_MAXBURSTLENGTH 262144 +#define DEFAULT_MAXRECVDATASEGMENTLENGTH 8192 +#define DEFAULT_INITIALR2T 1 +#define DEFAULT_IMMEDIATEDATA 1 +#define DEFAULT_DATAPDUINORDER 1 +#define DEFAULT_DATASEQUENCEINORDER 1 +#define DEFAULT_ERRORRECOVERYLEVEL 0 +#define DEFAULT_TIMEOUT 60 +#define DEFAULT_NOPININTERVAL 20 +#define DEFAULT_MAXR2T 16 +#define TMF_TIMEOUT 2 + +#define ISTGT_PG_TAG_MAX 0x0000ffff +#define ISTGT_LU_TAG_MAX 0x0000ffff +#define ISTGT_UC_TAG 0x00010000 +#define ISTGT_IOBUFSIZE (2 * 1024 * 1024) +#define ISTGT_SNSBUFSIZE 4096 +#define ISTGT_SHORTDATASIZE 8192 +#define ISTGT_SHORTPDUSIZE (48+4+ISTGT_SHORTDATASIZE+4) +#define ISTGT_CONDWAIT (50 * 1000) /* ms */ +#define ISTGT_CONDWAIT_MIN (5 * 1000) /* ms */ +#define ISTGT_CONDWAIT_MINS (5) /* s */ +#define ISTGT_STACKSIZE (2 * 1024 * 1024) + +#if defined (SIGRTMIN) +#define ISTGT_SIGWAKEUP (SIGRTMIN + 1) +#define ISTGT_USE_SIGRT +#elif defined (SIGIO) +#define ISTGT_SIGWAKEUP (SIGIO) +#else +#error "no signal for internal" +#endif +#if defined (__FreeBSD__) || (__linux__) || defined (__NetBSD__) || defined (__OpenBSD__) +#define ISTGT_USE_KQUEUE +#if defined (__linux__) || (__FreeBSD__) +#define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(void *)(f)) +#elif defined (__NetBSD__) +#define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(intptr_t)(f)) +#else +#define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(f)) +#endif +#endif + +#ifdef __linux__ +#define fls(lbPerRecord) (sizeof(int)*8 - __builtin_clz(lbPerRecord)) +#endif + +#define ISTGT_UCTL_UNXPATH "/var/run/istgt_ctl_sock" + +#define MTX_LOCK(MTX) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_mutex_lock((MTX))) != 0) { \ + ISTGT_ERRLOG("lock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) +#define MTX_UNLOCK(MTX) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_mutex_unlock((MTX))) != 0) { \ + ISTGT_ERRLOG("unlock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) +#define SPIN_LOCK(SPIN) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_spin_lock((SPIN))) != 0) { \ + ISTGT_ERRLOG("lock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) +#define SPIN_UNLOCK(SPIN) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_spin_unlock((SPIN))) != 0) { \ + ISTGT_ERRLOG("unlock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) + +typedef struct istgt_portal_t { + char *label; + char *host; + char *port; + int ref; + int idx; + int tag; + int que; + int sock; +} PORTAL; +typedef PORTAL *PORTAL_Ptr; + +typedef struct istgt_portal_group_t { + int nportals; + PORTAL **portals; + int ref; + int idx; + int tag; +} PORTAL_GROUP; +typedef PORTAL_GROUP *PORTAL_GROUP_Ptr; + +typedef struct istgt_initiator_group_t { + int ninitiators; + char **initiators; + int nnetmasks; + char **netmasks; + int ref; + int idx; + int tag; +} INITIATOR_GROUP; +typedef INITIATOR_GROUP *INITIATOR_GROUP_Ptr; + +typedef enum { + ISTGT_STATE_INVALID = 0, + ISTGT_STATE_INITIALIZED = 1, + ISTGT_STATE_RUNNING = 2, + ISTGT_STATE_EXITING = 3, + ISTGT_STATE_SHUTDOWN = 4, +} ISTGT_STATE; + +#define DEFAULT_ISTGT_SWMODE ISTGT_SWMODE_NORMAL +typedef enum { + ISTGT_SWMODE_TRADITIONAL = 0, + ISTGT_SWMODE_NORMAL = 1, + ISTGT_SWMODE_EXPERIMENTAL = 2, +} ISTGT_SWMODE; + +typedef struct istgt_t { + CONFIG *config; + CONFIG *config_old; + char *pidfile; + char *authfile; + char *logfile; +#if 0 + char *mediafile; + char *livefile; +#endif + char *mediadirectory; + char *nodebase; + + pthread_attr_t attr; + pthread_mutexattr_t mutex_attr; + pthread_mutex_t mutex; + pthread_mutex_t state_mutex; + pthread_mutex_t reload_mutex; + pthread_cond_t reload_cond; + + int inconfig; + int inmodify; + ISTGT_STATE state; + ISTGT_SWMODE swmode; + uint32_t generation; + int sig_pipe[2]; + int daemon; + int pg_reload; + + int nuctl_portal; + PORTAL uctl_portal[MAX_UCPORTAL]; + int nuctl_netmasks; + char **uctl_netmasks; + + int nportal_group; + PORTAL_GROUP portal_group[MAX_PORTAL_GROUP]; + int ninitiator_group; + INITIATOR_GROUP initiator_group[MAX_INITIATOR_GROUP]; + int nlogical_unit; + struct istgt_lu_t *logical_unit[MAX_LOGICAL_UNIT]; + + int timeout; + int nopininterval; + int maxr2t; + int no_discovery_auth; + int req_discovery_auth; + int req_discovery_auth_mutual; + int discovery_auth_group; + int no_uctl_auth; + int req_uctl_auth; + int req_uctl_auth_mutual; + int uctl_auth_group; + + int MaxSessions; + int MaxConnections; + int MaxOutstandingR2T; + int DefaultTime2Wait; + int DefaultTime2Retain; + int FirstBurstLength; + int MaxBurstLength; + int MaxRecvDataSegmentLength; + int InitialR2T; + int ImmediateData; + int DataPDUInOrder; + int DataSequenceInOrder; + int ErrorRecoveryLevel; + int OperationalMode; +} ISTGT; +typedef ISTGT *ISTGT_Ptr; + +int send_abrt_resp; +int abort_result_queue; +int wait_inflights; +int abort_release; +int clear_resv; + +char *istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2); +char *istgt_get_nval(CF_SECTION *sp, const char *key, int idx); +char *istgt_get_val(CF_SECTION *sp, const char *key); +int istgt_get_nintval(CF_SECTION *sp, const char *key, int idx); +int istgt_get_intval(CF_SECTION *sp, const char *key); +int istgt_reload(ISTGT *istgt); + +#ifdef USE_ATOMIC +static inline __attribute__((__always_inline__)) int +istgt_get_state(ISTGT_Ptr istgt) +{ + ISTGT_STATE state; +#if defined HAVE_ATOMIC_LOAD_ACQ_INT + state = atomic_load_acq_int((unsigned int *)&istgt->state); +#elif defined HAVE_ATOMIC_OR_UINT_NV + state = (int)atomic_or_uint_nv((unsigned int *)&istgt->state, 0); +#else +#error "no atomic operation" +#endif + return state; +} +static inline __attribute__((__always_inline__)) void +istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state) +{ +#if defined HAVE_ATOMIC_STORE_REL_INT + atomic_store_rel_int((unsigned int *)&istgt->state, state); +#elif defined HAVE_ATOMIC_SWAP_UINT + (void)atomic_swap_uint((unsigned int *)&istgt->state, state); +#if defined HAVE_MEMBAR_PRODUCER + membar_producer(); +#endif +#else +#error "no atomic operation" +#endif +} +#elif defined (USE_GCC_ATOMIC) +/* gcc >= 4.1 builtin functions */ +static inline __attribute__((__always_inline__)) int +istgt_get_state(ISTGT_Ptr istgt) +{ + ISTGT_STATE state; + state = __sync_fetch_and_add((unsigned int *)&istgt->state, 0); + return state; +} +static inline __attribute__((__always_inline__)) void +istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state) +{ + ISTGT_STATE state_old; + do { + state_old = __sync_fetch_and_add((unsigned int *)&istgt->state, 0); + } while (__sync_val_compare_and_swap((unsigned int *)&istgt->state, + state_old, state) != state_old); +#if defined (HAVE_GCC_ATOMIC_SYNCHRONIZE) + __sync_synchronize(); +#endif +} +#else /* !USE_ATOMIC && !USE_GCC_ATOMIC */ +static inline __attribute__((__always_inline__)) int +istgt_get_state(ISTGT_Ptr istgt) +{ + ISTGT_STATE state; + MTX_LOCK(&istgt->state_mutex); + state = istgt->state; + MTX_UNLOCK(&istgt->state_mutex); + return state; +} + +static inline __attribute__((__always_inline__)) void +istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state) +{ + MTX_LOCK(&istgt->state_mutex); + istgt->state = state; + MTX_UNLOCK(&istgt->state_mutex); +} +#endif /* USE_ATOMIC */ + +int is_unmap_enabled(void); +int is_persist_enabled(void); +#endif /* ISTGT_H */ diff --git a/src/istgt_cmd_table.c b/src/istgt_cmd_table.c new file mode 100644 index 00000000..d59b85ed --- /dev/null +++ b/src/istgt_cmd_table.c @@ -0,0 +1,1108 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2009 Silicon Graphics International Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_cmd_table.c#4 $ + * $FreeBSD: stable/9/sys/cam/ctl/ctl_cmd_table.c 237824 2012-06-29 21:27:37Z ken $ + */ +/* + * CAM Target Layer command table. + * + * Author: Ken Merry , Kim Le + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include + +#ifdef __FreeBSD__ +#include +#endif + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_md5.h" +#include "istgt_lu.h" +#include "istgt_iscsi.h" +#include "istgt_proto.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +/* + * Whenever support for a new command is added, it should be added to this + * table. + */ +struct istgt_cmd_entry istgt_cmd_table[] = +{ +/* 00 TEST UNIT READY */ +{ ISTGT_SERIDX_TUR, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_FLAG_DATA_NONE | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __TUR + }, + +/* 01 REWIND */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE , __UNK}, + +/* 02 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE , __UNK}, + +/* 03 REQUEST SENSE */ +{ ISTGT_SERIDX_RQ_SNS, ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_OK_ON_ALL_LUNS | + ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_NO_SENSE | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_OFFLINE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RQSNS + }, + +/* 04 FORMAT UNIT */ +{ ISTGT_SERIDX_FORMAT, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_FLAG_DATA_OUT, + __FMT + }, + +/* 05 READ BLOCK LIMITS */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __RBL}, + +/* 06 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 07 REASSIGN BLOCKS */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 08 READ(6) */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RD6 + }, + +/* 09 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK }, + +/* 0A WRITE(6) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_FLAG_DATA_OUT, + __WR6 +}, + +/* 0B SEEK(6) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 0C */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 0D */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 0E */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 0F READ REVERSE(6) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 10 WRITE FILEMARKS(6) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 11 SPACE(6) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 12 INQUIRY */ +{ ISTGT_SERIDX_INQ, ISTGT_CMD_FLAG_OK_ON_ALL_LUNS | + ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_NO_SENSE | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_OFFLINE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __INQ + }, + +/* 13 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 14 RECOVER BUFFERED DATA */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 15 MODE SELECT(6) */ +{ ISTGT_SERIDX_MD_SEL, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT, + __MSEL + }, + +/* 16 RESERVE(6) */ +{ ISTGT_SERIDX_RESV, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT, + __RSV6 + }, + +/* 17 RELEASE(6) */ +{ ISTGT_SERIDX_REL, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_NONE, + __REL6 + }, + +/* 18 COPY */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 19 ERASE(6) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 1A MODE SENSE(6) */ +{ ISTGT_SERIDX_MD_SNS, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN, + __MSN6 + }, + +/* 1B START STOP UNIT */ +{ ISTGT_SERIDX_START, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_OFFLINE | + ISTGT_FLAG_DATA_NONE | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __START + }, + +/* 1C RECEIVE DIAGNOSTIC RESULTS */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 1D SEND DIAGNOSTIC */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 1E PREVENT ALLOW MEDIUM REMOVAL */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 1F */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 20 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 21 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 22 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 23 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 24 SET WINDOW */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 25 READ CAPACITY(10) */ +{ ISTGT_SERIDX_RD_CAP, ISTGT_CMD_FLAG_OK_ON_SLUN| + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RCAP10 + }, + +/* 26 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 27 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 28 READ(10) */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RD10 + }, + +/* 29 READ GENERATION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 2A WRITE(10) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WR10 + }, + +/* 2B SEEK(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 2C ERASE(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 2D READ UPDATED BLOCK */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 2E WRITE AND VERIFY(10) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WV10 + }, + +/* 2F VERIFY(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 30 SEARCH DATA HIGH(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 31 SEARCH DATA EQUAL(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 32 SEARCH DATA LOW(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 33 SET LIMITS(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 34 PRE-FETCH(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __PREFTCH10}, + +/* 35 SYNCHRONIZE CACHE(10) */ +{ ISTGT_SERIDX_START, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_FLAG_DATA_NONE, + __SYC10 + }, + +/* 36 LOCK UNLOCK CACHE(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 37 READ DEFECT DATA(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __RDDEF}, + +/* 38 MEDIUM SCAN */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 39 COMPARE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 3A COPY AND VERIFY */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 3B WRITE BUFFER */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_PROC | + ISTGT_FLAG_DATA_OUT, + __WBF + }, + +/* 3C READ BUFFER */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 3D UPDATE BLOCK */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 3E READ LONG */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 3F WRITE LONG */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 40 CHANGE DEFINITION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 41 WRITE SAME(10) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN | ISTGT_FLAG_DATA_OUT, __WS10}, + +/* 42 READ SUB-CHANNEL */ +{ ISTGT_SERIDX_UNMAP, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, __UNMAP}, + +/* 43 READ TOC/PMA/ATIP */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 44 REPORT DENSITY SUPPORT */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 45 PLAY AUDIO(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 46 GET CONFIGURATION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 47 PLAY AUDIO MSF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 48 PLAY AUDIO TRACK INDEX */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 49 PLAY TRACK RELATIVE(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4A GET EVENT STATUS NOTIFICATION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4B PAUSE/RESUME */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4C LOG SELECT */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4D LOG SENSE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4E STOP PLAY/SCAN */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 4F */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 50 XDWRITE(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __XDW}, + +/* 51 XPWRITE(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __XDW}, + +/* 52 XDREAD(10) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __XDW}, + +/* 53 RESERVE TRACK */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 54 SEND OPC INFORMATION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 55 MODE SELECT(10) */ +{ ISTGT_SERIDX_MD_SEL, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT, + __MSEL10 + }, + +/* 56 RESERVE(10) */ +{ ISTGT_SERIDX_RESV, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT, + __RSV10 + }, + +/* 57 RELEASE(10) */ +{ ISTGT_SERIDX_REL, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT, + __REL10 + }, + +/* 58 REPAIR TRACK */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 59 READ MASTER CUE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 5A MODE SENSE(10) */ +{ ISTGT_SERIDX_MD_SNS, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN, + __MSN10 + }, + +/* 5B CLOSE TRACK/SESSION */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 5C READ BUFFER CAPACITY */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 5D SEND CUE SHEET */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 5E PERSISTENT RESERVE IN */ +{ ISTGT_SERIDX_PRES_IN, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __PRIN + }, + +//{ ISTGT_SERIDX_INVLD, __UNK}, + +/* 5F PERSISTENT RESERVE OUT */ +{ ISTGT_SERIDX_PRES_OUT, ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE| + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_OUT | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __PROUT + }, + +//{ ISTGT_SERIDX_INVLD, __UNK}, + +/* 60 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 61 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 62 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 63 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 64 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 65 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 66 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 67 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 68 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 69 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6A */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6B */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6C */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6D */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6E */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 6F */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 70 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 71 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 72 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 73 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 74 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 75 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 76 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 77 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 78 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 79 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7A */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7B */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7C */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7D */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7E */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 7F */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 80 XDWRITE EXTENDED(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __XDW}, + +/* 81 REBUILD(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 82 REGENERATE(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 83 EXTENDED COPY */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_ALL_LUNS | ISTGT_FLAG_DATA_OUT, __XCPY}, + +/* 84 RECEIVE COPY RESULTS */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_ALL_LUNS | ISTGT_FLAG_DATA_IN, __RCVCPY}, + +/* 85 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 86 ACCESS CONTROL IN */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 87 ACCESS CONTROL OUT */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 88 READ(16) */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_SLUN | ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RD16 + }, + +/* 89 COMPARE AND WRITE */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN | ISTGT_FLAG_DATA_OUT, + __ATS + }, + +/* 8A WRITE(16) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WR16 + }, + +/* 8B */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 8C READ ATTRIBUTE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 8D WRITE ATTRIBUTE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 8E WRITE AND VERIFY(16) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WV16 + }, + +/* 8F VERIFY(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 90 PRE-FETCH(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 91 SYNCHRONIZE CACHE(16) */ +{ ISTGT_SERIDX_START, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_FLAG_DATA_NONE, + __SYC16 + }, + +/* 92 LOCK UNLOCK CACHE(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 93 WRITE SAME(16) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN | ISTGT_FLAG_DATA_OUT, __WS16}, + +/* 94 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 95 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 96 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 97 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 98 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 99 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 9A */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 9B */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 9C */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 9D */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* 9E SERVICE ACTION IN(16) */ +/* XXX KDM not all service actions will be read capacity!! */ +{ ISTGT_SERIDX_RD_CAP, ISTGT_CMD_FLAG_OK_ON_SLUN | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RDCAP + }, + +/* 9F SERVICE ACTION OUT(16) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A0 REPORT LUNS */ +{ ISTGT_SERIDX_INQ, ISTGT_CMD_FLAG_OK_ON_ALL_LUNS | + ISTGT_CMD_FLAG_ALLOW_ON_RESV | + ISTGT_CMD_FLAG_NO_SENSE | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_OFFLINE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RLUN + }, + +/* A1 BLANK */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A2 SEND EVENT */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A3 MAINTENANCE (IN) Service Action - (0A) REPORT TARGET PORT GROUP */ +{ ISTGT_SERIDX_MAIN_IN, ISTGT_CMD_FLAG_OK_ON_BOTH | + ISTGT_CMD_FLAG_OK_ON_STOPPED | + ISTGT_CMD_FLAG_OK_ON_INOPERABLE | + ISTGT_CMD_FLAG_OK_ON_SECONDARY | + ISTGT_FLAG_DATA_IN, + __M_IN + }, + +/* A4 MAINTENANCE (OUT) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A5 MOVE MEDIUM */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A6 EXCHANGE MEDIUM */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A7 MOVE MEDIUM ATTACHED */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* A8 READ(12) */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_SLUN | ISTGT_FLAG_DATA_IN | + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV, + __RD12 + }, + +/* A9 PLAY TRACK RELATIVE(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* AA WRITE(12) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WR12 + }, + +/* AB SERVICE ACTION IN(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* AC ERASE(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* AD READ DVD STRUCTURE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* AE WRITE AND VERIFY(12) */ +{ ISTGT_SERIDX_WRITE, ISTGT_CMD_FLAG_OK_ON_SLUN| ISTGT_FLAG_DATA_OUT, + __WRV12 + }, + +/* AF VERIFY(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B0 SEARCH DATA HIGH(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B1 SEARCH DATA EQUAL(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B2 SEARCH DATA LOW(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B3 SET LIMITS(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B4 READ ELEMENT STATUS ATTACHED */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B5 REQUEST VOLUME ELEMENT ADDRESS */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B6 SEND VOLUME TAG */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B7 READ DEFECT DATA(12) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B8 READ ELEMENT STATUS */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* B9 READ CD MSF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BA REDUNDANCY GROUP (IN) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BB REDUNDANCY GROUP (OUT) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BC SPARE (IN) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BD SPARE (OUT) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BE VOLUME SET (IN) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* BF VOLUME SET (OUT) */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C0 - ISC_SEND_MSG_SHORT */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_PROC | ISTGT_FLAG_DATA_NONE, + __ISMx + }, + +/* C1 - ISC_SEND_MSG */ +{ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_PROC | ISTGT_FLAG_DATA_OUT, + __ISMx + }, + +/* C2 - ISC_WRITE */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_PROC | ISTGT_FLAG_DATA_OUT, + __ISMx + }, + +/* C3 - ISC_READ */ +{ ISTGT_SERIDX_READ, ISTGT_CMD_FLAG_OK_ON_PROC | ISTGT_FLAG_DATA_IN, + __ISMx + }, + +/* C4 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C5 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C6 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C7 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C8 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* C9 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CA */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CB */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CC */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CD */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* CF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D0 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D1 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D2 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D3 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D4 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D5 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D6 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D7 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D8 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* D9 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DA */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DB */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DC */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DD */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* DF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E0 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E1 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E2 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E3 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E4 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E5 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E6 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E7 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E8 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* E9 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* EA */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* EB */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* EC */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* ED */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* EE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* EF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F0 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F1 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F2 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F3 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F4 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F5 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F6 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F7 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F8 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* F9 */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FA */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FB */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FC */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FD */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FE */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK}, + +/* FF */ +{ ISTGT_SERIDX_INVLD, ISTGT_CMD_FLAG_NONE, __UNK} + +}; + +int iscsi_ops_indx_table[256] = { + NOPOUT, SCSI, TASK, LOGIN, TXT, DATAOUT, LOGOUT, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + SNACK, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, VEN_1C, VEN_1D, VEN_1E, UNDEF, + NOPIN, SCSI_RSP, TASK_RSP, LOGIN_RSP, TXT_RSP, DATAIN, LOGOUT_RSP, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, R2T, ASYNC, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, VEN_3C, VEN_3D, VEN_3E, REJECT, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, + UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF, UNDEF +}; + +char iscsi_ops[ISCSI_ARYSZ + 1] [15] = { + "NOPOUT", "SCSI", "TASK", "LOGIN", "TXT", "DATAOUT", "LOGOUT", "SNACK", "VEN_1C", "VEN_1D", "VEN_1E", + "NOPIN", "SCSI_RSP", "TASK_RSP", "LOGIN_RSP", "TXT_RSP", "DATAIN", "LOGOUT_RSP", "R2T", + "ASYNC", "VEN_3C", "VEN_3D", "VEN_3E", "REJECT", + "UNDEF", +}; +char scsi_ops[SCSI_ARYSZ + 1][20] = { + "TUR", + "REQ_SENSE", + "FMT_UNIT", + "RD_BL", + "RD6", + "WR6", + "INQ", + "MODE_SEL", + "RSV6", + "REL6", + "MODE_SENSE6", + "START_STOP_UNIT", + "RDCAP10", + "RD10", + "WR10", + "WR_V10", + "PREFETCH10", + "SYNC10", + "RD_DEFECT_DATA", + "WR_BUFFER", + "WR_SAME10", + "UNMAP", + "XDxx", + "MODE_SEL10", + "RSV10", + "REL10", + "MODE_SENSE10", + "PR_IN", + "PR_OUT", + "XCOPY", + "RCV_CPY_RSLTS", + "RD16", + "ATS", + "WR16", + "WR_V16", + "SYNC16", + "WR_SAME16", + "RDCAP_SAIN16", + "REPORT_LUNS", + "MAINT_IN", + "RD12", + "WR12", + "WR_V12", + "ISMXX", + "UNKNOWN" +}; diff --git a/src/istgt_conf.c b/src/istgt_conf.c new file mode 100644 index 00000000..e081cacd --- /dev/null +++ b/src/istgt_conf.c @@ -0,0 +1,557 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "istgt.h" +#include "istgt_misc.h" +#include "istgt_conf.h" + +//#define CF_DELIM " \t,;" +#define CF_DELIM " \t" + +static void istgt_free_all_cf_section(CF_SECTION *sp); +static void istgt_free_all_cf_item(CF_ITEM *ip); +static void istgt_free_all_cf_value(CF_VALUE *vp); +static void istgt_append_cf_item(CF_SECTION *sp, CF_ITEM *ip); +static void istgt_append_cf_value(CF_ITEM *ip, CF_VALUE *vp); + +CONFIG * +istgt_allocate_config(void) +{ + CONFIG *cp; + + cp = xmalloc(sizeof *cp); + memset(cp, 0, sizeof *cp); + cp->file = NULL; + cp->section = NULL; + + return cp; +} + +void +istgt_free_config(CONFIG *cp) +{ + if (cp == NULL) + return; + if (cp->section != NULL) { + istgt_free_all_cf_section(cp->section); + } + xfree(cp->file); + xfree(cp); +} + +static CF_SECTION * +istgt_allocate_cf_section(void) +{ + CF_SECTION *sp; + + sp = xmalloc(sizeof *sp); + memset(sp, 0, sizeof *sp); + sp->next = NULL; + sp->item = NULL; + + return sp; +} + +static void +istgt_free_cf_section(CF_SECTION *sp) +{ + if (sp == NULL) + return; + if (sp->item) { + istgt_free_all_cf_item(sp->item); + } + xfree(sp->name); + xfree(sp); +} + +static void +istgt_free_all_cf_section(CF_SECTION *sp) +{ + CF_SECTION *next; + + if (sp == NULL) + return; + while (sp != NULL) { + next = sp->next; + istgt_free_cf_section(sp); + sp = next; + } +} + +static CF_ITEM * +istgt_allocate_cf_item(void) +{ + CF_ITEM *ip; + + ip = xmalloc(sizeof *ip); + memset(ip, 0, sizeof *ip); + ip->next = NULL; + ip->key = NULL; + ip->val = NULL; + + return ip; +} + +static void +istgt_free_cf_item(CF_ITEM *ip) +{ + if (ip == NULL) + return; + if (ip->val != NULL) { + istgt_free_all_cf_value(ip->val); + } + xfree(ip->key); + xfree(ip); +} + +static void +istgt_free_all_cf_item(CF_ITEM *ip) +{ + CF_ITEM *next; + + if (ip == NULL) + return; + while (ip != NULL) { + next = ip->next; + istgt_free_cf_item(ip); + ip = next; + } +} + +static CF_VALUE * +istgt_allocate_cf_value(void) +{ + CF_VALUE *vp; + + vp = xmalloc(sizeof *vp); + memset(vp, 0, sizeof *vp); + vp->next = NULL; + vp->value = NULL; + + return vp; +} + +static void +istgt_free_cf_value(CF_VALUE *vp) +{ + if (vp == NULL) + return; + xfree(vp->value); + xfree(vp); +} + +static void +istgt_free_all_cf_value(CF_VALUE *vp) +{ + CF_VALUE *next; + + if (vp == NULL) + return; + while (vp != NULL) { + next = vp->next; + istgt_free_cf_value(vp); + vp = next; + } +} + +void +istgt_copy_cf_item(CF_SECTION *sp_dst, CF_SECTION *sp_src) +{ + CF_ITEM *ip, *ip_old; + CF_VALUE *vp, *vp_old; + + istgt_free_all_cf_item(sp_dst->item); + sp_dst->item = NULL; + + ip_old = sp_src->item; + while (ip_old != NULL) { + ip = istgt_allocate_cf_item(); + istgt_append_cf_item(sp_dst, ip); + ip->key = xstrdup(ip_old->key); + ip->val = NULL; + + vp_old = ip_old->val; + while (vp_old != NULL) { + vp = istgt_allocate_cf_value(); + istgt_append_cf_value(ip, vp); + vp->value = xstrdup(vp_old->value); + + vp_old = vp_old->next; + } + ip_old = ip_old->next; + } +} + +CF_SECTION * +istgt_find_cf_section(CONFIG *cp, const char *name) +{ + CF_SECTION *sp; + + if (name == NULL || name[0] == '\0') + return NULL; + + for (sp = cp->section; sp != NULL; sp = sp->next) { + if (sp->name != NULL && sp->name[0] == name[0] + && strcasecmp(sp->name, name) == 0) { + return sp; + } + } + + return NULL; +} + +static void +istgt_append_cf_section(CONFIG *cp, CF_SECTION *sp) +{ + CF_SECTION *last; + + if (cp == NULL) + return; + if (cp->section == NULL) { + cp->section = sp; + return; + } + for (last = cp->section; last->next != NULL; last = last->next) + ; + last->next = sp; +} + +CF_ITEM * +istgt_find_cf_nitem(CF_SECTION *sp, const char *key, int idx) +{ + CF_ITEM *ip; + int i; + + if (key == NULL || key[0] == '\0') + return NULL; + + i = 0; + for (ip = sp->item; ip != NULL; ip = ip->next) { + if (ip->key != NULL && ip->key[0] == key[0] + && strcasecmp(ip->key, key) == 0) { + if (i == idx) { + return ip; + } + i++; + } + } + + return NULL; +} + +CF_ITEM * +istgt_find_cf_item(CF_SECTION *sp, const char *key) +{ + return istgt_find_cf_nitem(sp, key, 0); +} + +static void +istgt_append_cf_item(CF_SECTION *sp, CF_ITEM *ip) +{ + CF_ITEM *last; + + if (sp == NULL) + return; + if (sp->item == NULL) { + sp->item = ip; + return; + } + for (last = sp->item; last->next != NULL; last = last->next) + ; + last->next = ip; +} + +static void +istgt_append_cf_value(CF_ITEM *ip, CF_VALUE *vp) +{ + CF_VALUE *last; + + if (ip == NULL) + return; + if (ip->val == NULL) { + ip->val = vp; + return; + } + for (last = ip->val; last->next != NULL; last = last->next) + ; + last->next = vp; +} + +static void +istgt_set_cf_section_type(CF_SECTION *sp) +{ + static struct cfst_table_t { + const char *name; + CF_SECTION_TYPE type; + } cfst_table[] = { + { "Global", ST_GLOBAL }, + { "UnitControl", ST_UNITCONTROL }, + { "PortalGroup", ST_PORTALGROUP }, + { "InitiatorGroup", ST_INITIATORGROUP }, + { "LogicalUnit", ST_LOGICAL_UNIT }, + { "AuthGroup", ST_AUTHGROUP }, + { NULL, ST_INVALID }, + }; + int i; + + if (sp == NULL || sp->name == NULL) + return; + for (i = 0; cfst_table[i].name != NULL; i++) { + if (sp->name[0] == cfst_table[i].name[0] + && strncasecmp(sp->name, cfst_table[i].name, + strlen(cfst_table[i].name)) == 0) { + sp->type = cfst_table[i].type; + return; + } + } + sp->type = ST_NONE; +} + +static int +parse_line(CONFIG *cp, char *lp) +{ + CF_SECTION *sp; + CF_ITEM *ip; + CF_VALUE *vp; + char *arg; + char *key; + char *val; + char *p; + int num; + + arg = trim_string(lp); + if (arg[0] == '[') { + /* section */ + arg++; + key = strsepq(&arg, "]"); + if (key == NULL || arg != NULL) { + fprintf(stderr, "broken section\n"); + return -1; + } + /* determine section number */ + for (p = key; *p != '\0' && !isdigit((int) *p); p++) + ; + if (*p != '\0') { + num = (int)strtol(p, NULL, 10); + } else { + num = 0; + } + + sp = istgt_find_cf_section(cp, key); + if (sp == NULL) { + sp = istgt_allocate_cf_section(); + istgt_append_cf_section(cp, sp); + } + cp->current_section = sp; + sp->name = xstrdup(key); + sp->num = num; + istgt_set_cf_section_type(sp); + } else { + /* parameters */ + sp = cp->current_section; + if (sp == NULL) { + fprintf(stderr, "unknown section\n"); + return -1; + } + key = strsepq(&arg, CF_DELIM); + if (key == NULL) { + fprintf(stderr, "broken key\n"); + return -1; + } + + ip = istgt_allocate_cf_item(); + istgt_append_cf_item(sp, ip); + ip->key = xstrdup(key); + ip->val = NULL; + if (arg != NULL) { + /* key has value(s) */ + while (arg != NULL) { + val = strsepq(&arg, CF_DELIM); + vp = istgt_allocate_cf_value(); + istgt_append_cf_value(ip, vp); + vp->value = xstrdup(val); + } + } + } + + return 0; +} + +static char * +fgets_line (FILE *fp) +{ +#define MAX_TMPBUFX 8192 + char *dst, *p, *tmp; + size_t total, len; + + dst = p = xmalloc(MAX_TMPBUFX); + dst[0] = '\0'; + total = 0; + + while (fgets(p, MAX_TMPBUFX, fp) != NULL) { + len = strlen(p); + total += len; + if (len + 1 < MAX_TMPBUFX || dst[total - 1] == '\n') { + //return realloc(dst, total + 1); + tmp = xmalloc(total + 5); + bcopy(dst, tmp, total); + tmp[total] = '\0'; + xfree(dst); + dst = tmp; + tmp = NULL; + return dst; + } + tmp = xmalloc(total + MAX_TMPBUFX); + bcopy(dst, tmp, total); + tmp[total] = '\0'; + xfree(dst); + dst = tmp; + tmp = NULL; + //dst = realloc (dst, total + MAX_TMPBUFX); + p = dst + total; + } + + if (feof(fp) && total != 0) { + tmp = xmalloc(total + 5); + bcopy(dst, tmp, total); + tmp[total] = '\n'; + tmp[total + 1] = '\0'; + xfree(dst); + dst = tmp; + tmp = NULL; + //dst = realloc(dst, total + 2); + //dst[total] = '\n'; + //dst[total + 1] = '\0'; + return dst; + } + + xfree(dst); + + return NULL; +} + +int +istgt_read_config(CONFIG *cp, const char *file) +{ + FILE *fp; + char *lp, *p; + char *lp2, *q; + int line; + int n, n2; + + if (file == NULL || file[0] == '\0') + return -1; + fp = fopen(file, "r"); + if (fp == NULL) { + fprintf(stderr, "open error: %s\n", file); + return -1; + } + cp->file = xstrdup(file); + + line = 1; + while ((lp = fgets_line(fp)) != NULL) { + /* skip spaces */ + for (p = lp; *p != '\0' && isspace((int) *p); p++) + ; + /* skip comment, empty line */ + if (p[0] == '#' || p[0] == '\0') + goto next_line; + + /* concatenate line end with '\' */ + n = strlen(p); + while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') { + n -= 2; + lp2 = fgets_line(fp); + if (lp2 == NULL) + break; + line++; + n2 = strlen(lp2); + q = xmalloc(n + n2 + 1); + memcpy(q, p, n); + memcpy(q + n, lp2, n2); + q[n + n2] = '\0'; + xfree(lp2); + xfree(lp); + p = lp = q; + n += n2; + } + + /* parse one line */ + if (parse_line(cp, p) < 0) { + fprintf(stderr, "parse error at line %d of %s\n", line, cp->file); + } + next_line: + line++; + xfree(lp); + } + + fclose(fp); + return 0; +} + +int +istgt_print_config(CONFIG *cp) +{ + CF_SECTION *sp; + CF_ITEM *ip; + CF_VALUE *vp; + + if (cp == NULL) + return -1; + + /* empty config? */ + sp = cp->section; + if (sp == NULL) + return 0; + + while (sp != NULL) { + printf("Section: %s\n", sp->name); + ip = sp->item; + while (ip != NULL) { + printf(" Item: %s ", ip->key); + vp = ip->val; + while (vp != NULL) { + printf("Val: %s ", vp->value); + vp = vp->next; + } + printf("\n"); + ip = ip->next; + } + sp = sp->next; + } + + return 0; +} diff --git a/src/istgt_conf.h b/src/istgt_conf.h new file mode 100644 index 00000000..bc04bfb8 --- /dev/null +++ b/src/istgt_conf.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_CONF_H +#define ISTGT_CONF_H + +typedef struct config_value_t { + struct config_value_t *next; + char *value; +} CF_VALUE; + +typedef struct config_item_t { + struct config_item_t *next; + char *key; + CF_VALUE *val; +} CF_ITEM; + +typedef enum +{ + ST_INVALID = -1, + ST_NONE = 0, + ST_GLOBAL, + ST_UNITCONTROL, + ST_PORTALGROUP, + ST_INITIATORGROUP, + ST_LOGICAL_UNIT, + ST_AUTHGROUP, +} CF_SECTION_TYPE; + +typedef struct config_section_t +{ + struct config_section_t *next; + CF_SECTION_TYPE type; + char *name; + int num; + CF_ITEM *item; +} CF_SECTION; + +typedef struct config_t +{ + char *file; + CF_SECTION *current_section; + CF_SECTION *section; +} CONFIG; + +CONFIG *istgt_allocate_config(void); +void istgt_free_config(CONFIG *cp); +void istgt_copy_cf_item(CF_SECTION *sp_dst, CF_SECTION *sp_src); +CF_SECTION *istgt_find_cf_section(CONFIG *cp, const char *name); +CF_ITEM *istgt_find_cf_nitem(CF_SECTION *sp, const char *key, int idx); +CF_ITEM *istgt_find_cf_item(CF_SECTION *sp, const char *key); +int istgt_read_config(CONFIG *cp, const char *file); +int istgt_print_config(CONFIG *cp); + +#endif /* ISTGT_CONF_H */ diff --git a/src/istgt_crc32c.c b/src/istgt_crc32c.c new file mode 100644 index 00000000..3f1285e9 --- /dev/null +++ b/src/istgt_crc32c.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#endif + +#include "istgt_iscsi.h" +#include "istgt_crc32c.h" + +/* defined in RFC3720(12.1) */ +static uint32_t istgt_crc32c_initial = ISTGT_CRC32C_INITIAL; +static uint32_t istgt_crc32c_xor = ISTGT_CRC32C_XOR; +static uint32_t istgt_crc32c_polynomial = ISTGT_CRC32C_POLYNOMIAL; +#ifdef ISTGT_USE_CRC32C_TABLE +static uint32_t istgt_crc32c_table[256]; +static int istgt_crc32c_initialized = 0; +#endif /* ISTGT_USE_CRC32C_TABLE */ + +static uint32_t +istgt_reflect(uint32_t val, int bits) +{ + int i; + uint32_t r; + + if (bits < 1 || bits > 32) + return 0; + r = 0; + for (i = 0; i < bits; i++) { + r |= ((val >> ((bits - 1) - i)) & 1) << i; + } + return r; +} + +#ifdef ISTGT_USE_CRC32C_TABLE +void +istgt_init_crc32c_table(void) +{ + int i, j; + uint32_t val; + uint32_t reflect_polynomial; + + reflect_polynomial = istgt_reflect(istgt_crc32c_polynomial, 32); + for (i = 0; i < 256; i++) { + val = i; + for (j = 0; j < 8; j++) { + if (val & 1) { + val = (val >> 1) ^ reflect_polynomial; + } else { + val = (val >> 1); + } + } + istgt_crc32c_table[i] = val; + } + istgt_crc32c_initialized = 1; +} +#endif /* ISTGT_USE_CRC32C_TABLE */ + +uint32_t +istgt_update_crc32c(const uint8_t *buf, size_t len, uint32_t crc) +{ + size_t s; +#ifndef ISTGT_USE_CRC32C_TABLE + int i; + uint32_t val; + uint32_t reflect_polynomial; +#endif /* ISTGT_USE_CRC32C_TABLE */ + +#ifdef ISTGT_USE_CRC32C_TABLE +#if 0 + /* initialize by main() */ + if (!istgt_crc32c_initialized) { + istgt_init_crc32c_table(); + } +#endif +#else + reflect_polynomial = istgt_reflect(istgt_crc32c_polynomial, 32); +#endif /* ISTGT_USE_CRC32C_TABLE */ + + for (s = 0; s < len; s++) { +#ifdef ISTGT_USE_CRC32C_TABLE + crc = (crc >> 8) ^ istgt_crc32c_table[(crc ^ buf[s]) & 0xff]; +#else + val = buf[s]; + for (i = 0; i < 8; i++) { + if ((crc ^ val) & 1) { + crc = (crc >> 1) ^ reflect_polynomial; + } else { + crc = (crc >> 1); + } + val = val >> 1; + } +#endif /* ISTGT_USE_CRC32C_TABLE */ + } + return crc; +} + +uint32_t +istgt_fixup_crc32c(size_t total, uint32_t crc) +{ + uint8_t padding[ISCSI_ALIGNMENT]; + size_t pad_length; + size_t rest; + + if (total == 0) + return crc; +#if 0 + /* alignment must be power of 2 */ + rest = total & ~(ISCSI_ALIGNMENT - 1); +#endif + rest = total % ISCSI_ALIGNMENT; + if (rest != 0) { + pad_length = ISCSI_ALIGNMENT; + pad_length -= rest; + if (pad_length > 0 && pad_length < sizeof padding){ + memset(padding, 0, sizeof padding); + crc = istgt_update_crc32c(padding, pad_length, crc); + } + } + return crc; +} + +uint32_t +istgt_crc32c(const uint8_t *buf, size_t len) +{ + uint32_t crc32c; + + crc32c = istgt_crc32c_initial; + crc32c = istgt_update_crc32c(buf, len, crc32c); + if ((len % ISCSI_ALIGNMENT) != 0) { + crc32c = istgt_fixup_crc32c(len, crc32c); + } + crc32c = crc32c ^ istgt_crc32c_xor; + return crc32c; +} + +uint32_t +istgt_iovec_crc32c(const struct iovec *iovp, int iovc, uint32_t offset, uint32_t len) +{ + const uint8_t *p; + uint32_t total; + uint32_t pos; + uint32_t n; + uint32_t crc32c; + int i; + + pos = 0; + total = 0; + crc32c = istgt_crc32c_initial; + for (i = 0; i < iovc; i++) { + if (len == 0) + break; + if (pos + iovp[i].iov_len > offset) { + p = (const uint8_t *) iovp[i].iov_base + (offset - pos); + if (iovp[i].iov_len > len) { + n = len; + len = 0; + } else { + n = iovp[i].iov_len; + len -= n; + } + crc32c = istgt_update_crc32c(p, n, crc32c); + offset += n; + total += n; + } + pos += iovp[i].iov_len; + } +#if 0 + printf("update %d bytes\n", total); +#endif + crc32c = istgt_fixup_crc32c(total, crc32c); + crc32c = crc32c ^ istgt_crc32c_xor; + return crc32c; +} diff --git a/src/istgt_crc32c.h b/src/istgt_crc32c.h new file mode 100644 index 00000000..419bba50 --- /dev/null +++ b/src/istgt_crc32c.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_CRC32C_H +#define ISTGT_CRC32C_H + +#include +#include + +#ifdef __FreeBSD__ +#include +#endif + +#define ISTGT_USE_CRC32C_TABLE +#define ISTGT_CRC32C_INITIAL 0xffffffffUL +#define ISTGT_CRC32C_XOR 0xffffffffUL +#define ISTGT_CRC32C_POLYNOMIAL 0x1edc6f41UL + +void istgt_init_crc32c_table(void); +uint32_t istgt_update_crc32c(const uint8_t *buf, size_t len, uint32_t crc); +uint32_t istgt_fixup_crc32c(size_t total, uint32_t crc); +uint32_t istgt_crc32c(const uint8_t *buf, size_t len); +uint32_t istgt_iovec_crc32c(const struct iovec *iovp, int iovc, uint32_t offset, uint32_t len); + +#endif /* ISTGT_CRC32C_H */ diff --git a/src/istgt_iscsi.c b/src/istgt_iscsi.c new file mode 100644 index 00000000..dc05c12c --- /dev/null +++ b/src/istgt_iscsi.c @@ -0,0 +1,7380 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include + +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#define DIO_ISCSIWR _IOW('d', 131, struct istgt_detail) +#endif + +#ifdef __linux__ +#include +#endif + +#include +#include + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_conf.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_crc32c.h" +#include "istgt_md5.h" +#include "istgt_iscsi.h" +#include "istgt_iscsi_param.h" +#include "istgt_lu.h" +#include "istgt_proto.h" +#include "istgt_scsi.h" +#include "istgt_queue.h" + +#include + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +/* according to RFC1982 */ +#define SN32_CMPMAX (((uint32_t)1U) << (32 - 1)) +#define SN32_LT(S1,S2) \ + (((uint32_t)(S1) != (uint32_t)(S2)) \ + && (((uint32_t)(S1) < (uint32_t)(S2) \ + && ((uint32_t)(S2) - (uint32_t)(S1) < SN32_CMPMAX)) \ + || ((uint32_t)(S1) > (uint32_t)(S2) \ + && ((uint32_t)(S1) - (uint32_t)(S2) > SN32_CMPMAX)))) +#define SN32_GT(S1,S2) \ + (((uint32_t)(S1) != (uint32_t)(S2)) \ + && (((uint32_t)(S1) < (uint32_t)(S2) \ + && ((uint32_t)(S2) - (uint32_t)(S1) > SN32_CMPMAX)) \ + || ((uint32_t)(S1) > (uint32_t)(S2) \ + && ((uint32_t)(S1) - (uint32_t)(S2) < SN32_CMPMAX)))) + +#define POLLWAIT 5000 +#define MAX_MCSREVWAIT (10 * 1000) +#define ISCMDQ 8 +#define ISCSI_SOCKET "/dev/eventctl" + +enum iscsi_log { + TYPE_LOGIN, + TYPE_LOGOUT, + TYPE_CONNBRK +}; +struct istgt_detail { + + enum iscsi_log login_status; + /* IP address */ + char initiator_addr[64]; + char target_addr[64]; + + /* Initiator/Target name */ + char initiator_name[256]; + char target_name[256]; +}; + +#define ISCSI_GETVAL(PARAMS,KEY) \ + istgt_iscsi_param_get_val((PARAMS),(KEY)) +#define ISCSI_EQVAL(PARAMS,KEY,VAL) \ + istgt_iscsi_param_eq_val((PARAMS),(KEY),(VAL)) +#define ISCSI_DELVAL(PARAMS,KEY) \ + istgt_iscsi_param_del((PARAMS),(KEY)) +#define ISCSI_ADDVAL(PARAMS,KEY,VAL,LIST,TYPE) \ + istgt_iscsi_param_add((PARAMS),(KEY),(VAL), (LIST), (TYPE)) + +static int g_nconns; +static int g_max_connidx; +static CONN_Ptr *g_conns; +static pthread_mutex_t g_conns_mutex; + +static uint16_t g_last_tsih; +static pthread_mutex_t g_last_tsih_mutex; + +static int istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); +static void istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN); +static void istgt_clear_all_transfer_task(CONN_Ptr conn); +static int istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN); +static int istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid); +static void istgt_remove_conn(CONN_Ptr conn); +static int istgt_iscsi_drop_all_conns(CONN_Ptr conn); +static int istgt_iscsi_drop_old_conns(CONN_Ptr conn); +static void ioctl_call(CONN_Ptr, enum iscsi_log); + +//_verb_stat SCSIstat_0min[SCSI_ARYSZ] +//_verb_stat SCSIstat_1min[SCSI_ARYSZ] +_verb_stat SCSIstat_rest[SCSI_ARYSZ] = { {0,0,0} }; +_verb_istat ISCSIstat_rest[ISCSI_ARYSZ] = { {0,0,0} }; +extern int iscsi_ops_indx_table[256]; + +/* Switch to use readv/writev (assume blocking) */ +#define ISTGT_USE_IOVEC + +#define MATCH_DIGEST_WORD(BUF, CRC32C) \ + ( ((((uint32_t) *((uint8_t *)(BUF)+0)) << 0) \ + | (((uint32_t) *((uint8_t *)(BUF)+1)) << 8) \ + | (((uint32_t) *((uint8_t *)(BUF)+2)) << 16) \ + | (((uint32_t) *((uint8_t *)(BUF)+3)) << 24)) \ + == (CRC32C)) + +#define MAKE_DIGEST_WORD(BUF, CRC32C) \ + ( ((*((uint8_t *)(BUF)+0)) = (uint8_t)((uint32_t)(CRC32C) >> 0)), \ + ((*((uint8_t *)(BUF)+1)) = (uint8_t)((uint32_t)(CRC32C) >> 8)), \ + ((*((uint8_t *)(BUF)+2)) = (uint8_t)((uint32_t)(CRC32C) >> 16)), \ + ((*((uint8_t *)(BUF)+3)) = (uint8_t)((uint32_t)(CRC32C) >> 24))) + +#if 0 +static int +istgt_match_digest_word(const uint8_t *buf, uint32_t crc32c) +{ + uint32_t l; + + l = (buf[0] & 0xffU) << 0; + l |= (buf[1] & 0xffU) << 8; + l |= (buf[2] & 0xffU) << 16; + l |= (buf[3] & 0xffU) << 24; + return (l == crc32c); +} + +static uint8_t * +istgt_make_digest_word(uint8_t *buf, size_t len, uint32_t crc32c) +{ + if (len < ISCSI_DIGEST_LEN) + return NULL; + + buf[0] = (crc32c >> 0) & 0xffU; + buf[1] = (crc32c >> 8) & 0xffU; + buf[2] = (crc32c >> 16) & 0xffU; + buf[3] = (crc32c >> 24) & 0xffU; + return buf; +} +#endif + + + +extern clockid_t clockid; +static int +istgt_iscsi_read_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + struct iovec iovec[4]; /* AHS+HD+DATA+DD */ + uint32_t crc32c; + int nbytes; + int total_ahs_len; + int data_len; + int adata_len = 0; + int segment_len; + int total; + int rc; + int i; + struct timespec now; + int opcode; + pdu->ahs = NULL; + pdu->total_ahs_len = 0; + pdu->data = NULL; + pdu->data_segment_len = 0; + pdu->opcode = -1; + total = 0; + + /* BHS (require for all PDU) */ + //ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS read %d\n", + // ISCSI_BHS_LEN); + errno = 0; + clock_gettime(clockid, &pdu->start0); + rc = recv(conn->sock, &pdu->bhs, ISCSI_BHS_LEN, MSG_WAITALL); + if (rc < 0) { + clock_gettime(clockid, &now); + if (errno == ECONNRESET) { + ISTGT_WARNLOG("Connection reset by peer (%s,time=%lu)\n", + conn->initiator_name, (unsigned long)(now.tv_sec - pdu->start0.tv_sec)); + conn->state = CONN_STATE_EXITING; + } else if (errno == ETIMEDOUT) { + ISTGT_WARNLOG("Operation timed out (%s,time=%lu)\n", + conn->initiator_name, (unsigned long)(now.tv_sec - pdu->start0.tv_sec)); + conn->state = CONN_STATE_EXITING; + } else { + ISTGT_ERRLOG("iscsi_read() failed (errno=%d,%s,time=%lu)\n", + errno, conn->initiator_name, (unsigned long)(now.tv_sec - pdu->start0.tv_sec)); + } + return -1; + } + if (rc == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "recv() EOF (%s)\n", + conn->initiator_name); + conn->state = CONN_STATE_EXITING; + return -1; + } + if (rc != ISCSI_BHS_LEN) { + ISTGT_ERRLOG("invalid BHS length (%d,%s)\n", rc, conn->initiator_name); + return -1; + } + total += ISCSI_BHS_LEN; + + opcode = BGET8W(&pdu->bhs.opcode, 5, 6); + pdu->opcode = (uint8_t)opcode; + ISCSIstat_rest[ iscsi_ops_indx_table[pdu->opcode] ].opcode = opcode; + ++ISCSIstat_rest[ iscsi_ops_indx_table[pdu->opcode] ].pdu_read; + + /* AHS */ + total_ahs_len = DGET8(&pdu->bhs.total_ahs_len); + if (total_ahs_len != 0) { + pdu->ahs = xmalloc(ISCSI_ALIGN((4 * total_ahs_len))); + pdu->total_ahs_len = total_ahs_len; + total += (4 * total_ahs_len); + } else { + pdu->ahs = NULL; + pdu->total_ahs_len = 0; + } + iovec[0].iov_base = pdu->ahs; + iovec[0].iov_len = 4 * pdu->total_ahs_len; + + /* Header Digest */ + iovec[1].iov_base = pdu->header_digest; + if (conn->header_digest) { + iovec[1].iov_len = ISCSI_DIGEST_LEN; + total += ISCSI_DIGEST_LEN; + } else { + iovec[1].iov_len = 0; + } + + /* Data Segment */ + data_len = DGET24(&pdu->bhs.data_segment_len[0]); + if (data_len != 0) { + if (conn->sess == NULL) { + segment_len = DEFAULT_FIRSTBURSTLENGTH; + } else { + segment_len = conn->MaxRecvDataSegmentLength; + } + if (data_len > segment_len) { + ISTGT_ERRLOG("Data(%d) > Segment(%d)\n", + data_len, segment_len); + return -1; + } + //pdu->data = xmalloc(ISCSI_ALIGN(segment_len)); + pdu->data_segment_len = data_len; + adata_len = ISCSI_ALIGN(data_len); + pdu->data = xmalloc(adata_len+400); + total += adata_len; + } else { + pdu->data = NULL; + pdu->data_segment_len = 0; + } + iovec[2].iov_base = pdu->data; + iovec[2].iov_len = ISCSI_ALIGN(pdu->data_segment_len); + + /* Data Digest */ + iovec[3].iov_base = pdu->data_digest; + if (conn->data_digest && data_len != 0) { + iovec[3].iov_len = ISCSI_DIGEST_LEN; + total += ISCSI_DIGEST_LEN; + } else { + iovec[3].iov_len = 0; + } + + /* read all bytes to iovec */ + nbytes = total - ISCSI_BHS_LEN; + if (nbytes > 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU read %d (data:%ld ahs:%lu)\n", nbytes, pdu->data_segment_len, pdu->total_ahs_len); + } + clock_gettime(clockid, &pdu->start); + errno = 0; + while (nbytes > 0) { + rc = readv(conn->sock, &iovec[0], 4); + if (rc < 0) { + clock_gettime(clockid, &now); //time(NULL); + ISTGT_ERRLOG("readv() failed (%d,errno=%d,%s,time=%lu)\n", + rc, errno, conn->initiator_name, (unsigned long)(now.tv_sec - pdu->start.tv_sec)); + return -1; + } + if (rc == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "readv() EOF (%s)\n", + conn->initiator_name); + conn->state = CONN_STATE_EXITING; + return -1; + } + nbytes -= rc; + if (nbytes == 0) + break; + /* adjust iovec length */ + for (i = 0; i < 4; i++) { + if (iovec[i].iov_len != 0 && iovec[i].iov_len > (size_t)rc) { + iovec[i].iov_base + = (void *) (((uintptr_t)iovec[i].iov_base) + rc); + iovec[i].iov_len -= rc; + break; + } else { + rc -= iovec[i].iov_len; + iovec[i].iov_len = 0; + } + } + } + + /* check digest */ + if (conn->header_digest) { + if (total_ahs_len == 0) { + crc32c = istgt_crc32c((uint8_t *) &pdu->bhs, + ISCSI_BHS_LEN); + } else { + int upd_total = 0; + crc32c = ISTGT_CRC32C_INITIAL; + crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs, + ISCSI_BHS_LEN, crc32c); + upd_total += ISCSI_BHS_LEN; + crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs, + (4 * total_ahs_len), crc32c); + upd_total += (4 * total_ahs_len); + crc32c = istgt_fixup_crc32c(upd_total, crc32c); + crc32c = crc32c ^ ISTGT_CRC32C_XOR; + } + rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c); + if (rc == 0) { + ISTGT_ERRLOG("header digest error (%s)\n", conn->initiator_name); + return -1; + } + } + if (conn->data_digest && data_len != 0) { + crc32c = istgt_crc32c(pdu->data, ISCSI_ALIGN(data_len)); + rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c); + if (rc == 0) { + ISTGT_ERRLOG("data digest error (%s)\n", conn->initiator_name); + return -1; + } + } + + return total; +} + +static int istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu); +static int istgt_iscsi_write_pdu_queue(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int req_type, int I_bit); + +uint8_t istgt_get_sleep_val(ISTGT_LU_DISK *spec); + +static int istgt_update_pdu(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + uint8_t *rsp; + uint32_t task_tag; + int opcode; + int I_bit; + ISTGT_LU_DISK *spec; + uint8_t sleep_val; + + I_bit = lu_cmd->I_bit; + rsp = (uint8_t *) &lu_cmd->pdu->bhs; + opcode = BGET8W(&rsp[0], 5, 6); + task_tag = DGET32(&rsp[16]); + if ((opcode == ISCSI_OP_R2T) + || (opcode == ISCSI_OP_NOPIN && task_tag == 0xffffffffU)) { + + if(opcode == ISCSI_OP_R2T) + { + spec = (ISTGT_LU_DISK *)(conn->sess->lu->lun[0].spec); + if(spec->error_inject & SEND_R2T) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep_val = istgt_get_sleep_val(spec); + sleep(sleep_val); + } + } + + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + } else if ((opcode == ISCSI_OP_TASK_RSP) + || (opcode == ISCSI_OP_NOPIN && task_tag != 0xffffffffU)) { + + if(opcode == ISCSI_OP_TASK_RSP) + { + spec = (ISTGT_LU_DISK *)(conn->sess->lu->lun[0].spec); + if(spec->error_inject & SEND_TASK_RSP) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep_val = istgt_get_sleep_val(spec); + sleep(sleep_val); + } + } + + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + if (I_bit == 0) { + if(likely(lu_cmd->lu->limit_q_size == 0 || ((int)(conn->sess->MaxCmdSN - conn->sess->ExpCmdSN) < lu_cmd->lu->limit_q_size))) { + conn->sess->ExpCmdSN++; + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + if(unlikely((conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local) && (lu_cmd->lu->limit_q_size == 0))) { + ISTGT_LOG("conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local in tsk_rsp\n"); + conn->sess->MaxCmdSN = conn->sess->MaxCmdSN_local; + } + } else { + conn->sess->ExpCmdSN++; + conn->sess->MaxCmdSN_local++; + } + } + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + } + return 0; +} + +static int +istgt_iscsi_write_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + return istgt_iscsi_write_pdu_queue(conn, pdu, ISTGT_LU_TASK_REQPDU, 0); +} + +static int +istgt_iscsi_write_pdu_upd(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int I_bit) +{ + return istgt_iscsi_write_pdu_queue(conn, pdu, ISTGT_LU_TASK_REQUPDPDU, I_bit); +} + +static int +istgt_iscsi_write_pdu_queue(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int req_type, int I_bit) +{ + int rc = 0; + ISTGT_QUEUE_Ptr r_ptr = NULL; + ISTGT_LU_TASK_Ptr lu_task; + ISCSI_PDU_Ptr src_pdu, dst_pdu; + uint8_t *cp; + int total_ahs_len; + int data_len; + int alloc_len; + int total; + + cp = (uint8_t *) &pdu->bhs; + total_ahs_len = DGET8(&cp[4]); + data_len = DGET24(&cp[5]); + total = 0; + +#if 0 + ISTGT_LOG("W:PDU OP=%x, tag=%x, ExpCmdSN=%u, MaxCmdSN=%u\n", + DGET8(&cp[0]), DGET32(&cp[32]), DGET32(&cp[28]), DGET32(&cp[32])); +#endif + /* allocate for queued PDU */ + alloc_len = ISCSI_ALIGN(sizeof *lu_task); + alloc_len += ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu); + //alloc_len += ISCSI_ALIGN(4 * total_ahs_len); + //alloc_len += ISCSI_ALIGN(data_len); + lu_task = xmalloc(alloc_len); + memset(lu_task, 0, alloc_len); + lu_task->lu_cmd.pdu = (ISCSI_PDU_Ptr) ((uintptr_t)lu_task + + ISCSI_ALIGN(sizeof *lu_task)); + //lu_task->lu_cmd.pdu->ahs = (ISCSI_AHS *) ((uintptr_t)lu_task->lu_cmd.pdu + // + ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu)); + //lu_task->lu_cmd.pdu->data = (uint8_t *) ((uintptr_t)lu_task->lu_cmd.pdu->ahs + // + ISCSI_ALIGN(4 * total_ahs_len)); + + /* specify type and self conn */ + //lu_task->type = ISTGT_LU_TASK_REQPDU; + lu_task->type = req_type; + lu_task->conn = conn; + + /* extra flags */ + lu_task->lu_cmd.I_bit = I_bit; + + clock_gettime(clockid, &lu_task->lu_cmd.times[0]); + lu_task->lu_cmd.caller[0] = 't'; + lu_task->lu_cmd._andx = 0; + lu_task->lu_cmd._lst = 0; + lu_task->lu_cmd.infdx = 0; + lu_task->lu_cmd.infcpy = 0; + + //aj ++ISCSIstat_rest[ iscsi_ops_indx_table[opcode] ].res_start; + + /* copy PDU structure */ + src_pdu = pdu; + dst_pdu = lu_task->lu_cmd.pdu; + memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN); + total += ISCSI_BHS_LEN; + if (total_ahs_len != 0) { + dst_pdu->ahs = src_pdu->ahs; + dst_pdu->total_ahs_len = (4 * total_ahs_len); + total += (4 * total_ahs_len); + src_pdu->ahs = NULL; src_pdu->total_ahs_len = 0; + } else { + dst_pdu->ahs = NULL; dst_pdu->total_ahs_len = 0; + } + if (conn->header_digest) { + dst_pdu->header_digestX = src_pdu->header_digestX; + total += ISCSI_DIGEST_LEN; + } else { + dst_pdu->header_digestX = 0; + } + if (data_len != 0) { + dst_pdu->data_segment_len = data_len; + dst_pdu->data = src_pdu->data; + src_pdu->data = NULL; src_pdu->data_segment_len = 0; + total += data_len; + } else { + dst_pdu->data = NULL; dst_pdu->data_segment_len = 0; + } + if (conn->data_digest && data_len != 0) { + dst_pdu->data_digestX = src_pdu->data_digestX; + total += ISCSI_DIGEST_LEN; + } else { + dst_pdu->data_digestX = 0; + } + + /* insert to queue */ + MTX_LOCK(&conn->result_queue_mutex); + r_ptr = istgt_queue_enqueue(&conn->result_queue, lu_task); + if (r_ptr == NULL) { + MTX_UNLOCK(&conn->result_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + return -1; + } + /* notify to thread */ + if(conn->sender_waiting == 1) + rc = pthread_cond_broadcast(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + if (rc != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + return -1; + } + + /* total bytes should be sent in queue */ + rc = total; + return rc; +} + +static int +istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + struct iovec iovec[5]; /* BHS+AHS+HD+DATA+DD */ + uint8_t *cp; + uint32_t crc32c; + time_t start, now; + int nbytes; + int enable_digest; + int opcode; + int total_ahs_len; + int data_len; + int total; + int rc; + int i; + + cp = (uint8_t *) &pdu->bhs; + total_ahs_len = DGET8(&cp[4]); + data_len = DGET24(&cp[5]); + total = 0; + + enable_digest = 1; + opcode = BGET8W(&cp[0], 5, 6); + if (opcode == ISCSI_OP_LOGIN_RSP) { + /* this PDU should be sent without digest */ + enable_digest = 0; + } + ISCSIstat_rest[ iscsi_ops_indx_table[(uint8_t)opcode] ].opcode = (uint8_t)opcode; + ++ISCSIstat_rest[ iscsi_ops_indx_table[(uint8_t)opcode] ].pdu_sent; + + /* BHS */ + iovec[0].iov_base = &pdu->bhs; + iovec[0].iov_len = ISCSI_BHS_LEN; + total += ISCSI_BHS_LEN; + + /* AHS */ + iovec[1].iov_base = pdu->ahs; + iovec[1].iov_len = 4 * total_ahs_len; + total += (4 * total_ahs_len); + + /* Header Digest */ + iovec[2].iov_base = pdu->header_digest; + if (enable_digest && conn->header_digest) { + if (total_ahs_len == 0) { + crc32c = istgt_crc32c((uint8_t *) &pdu->bhs, + ISCSI_BHS_LEN); + } else { + int upd_total = 0; + crc32c = ISTGT_CRC32C_INITIAL; + crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs, + ISCSI_BHS_LEN, crc32c); + upd_total += ISCSI_BHS_LEN; + crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs, + (4 * total_ahs_len), crc32c); + upd_total += (4 * total_ahs_len); + crc32c = istgt_fixup_crc32c(upd_total, crc32c); + crc32c = crc32c ^ ISTGT_CRC32C_XOR; + } + MAKE_DIGEST_WORD(pdu->header_digest, crc32c); + + iovec[2].iov_len = ISCSI_DIGEST_LEN; + total += ISCSI_DIGEST_LEN; + } else { + iovec[2].iov_len = 0; + } + + /* Data Segment */ + iovec[3].iov_base = pdu->data; + iovec[3].iov_len = ISCSI_ALIGN(data_len); + total += ISCSI_ALIGN(data_len); + + /* Data Digest */ + iovec[4].iov_base = pdu->data_digest; + if (enable_digest && conn->data_digest && data_len != 0) { + crc32c = istgt_crc32c(pdu->data, ISCSI_ALIGN(data_len)); + MAKE_DIGEST_WORD(pdu->data_digest, crc32c); + + iovec[4].iov_len = ISCSI_DIGEST_LEN; + total += ISCSI_DIGEST_LEN; + } else { + iovec[4].iov_len = 0; + } + + /* write all bytes from iovec */ + nbytes = total; + ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU write %d[%lu, %lu/%lu]\n", nbytes, iovec[1].iov_len, iovec[3].iov_len, iovec[4].iov_len); + errno = 0; + start = time(NULL); + while (nbytes > 0) { + rc = writev(conn->sock, &iovec[0], 5); + if (rc < 0) { + now = time(NULL); + ISTGT_ERRLOG("writev() failed (errno=%d,%s,time=%f)\n", + errno, conn->initiator_name, difftime(now, start)); + return -1; + } + nbytes -= rc; + if (nbytes == 0) + break; + /* adjust iovec length */ + for (i = 0; i < 5; i++) { + if (iovec[i].iov_len != 0 && iovec[i].iov_len > (size_t)rc) { + iovec[i].iov_base + = (void *) (((uintptr_t)iovec[i].iov_base) + rc); + iovec[i].iov_len -= rc; + break; + } else { + rc -= iovec[i].iov_len; + iovec[i].iov_len = 0; + } + } + } + + return total; +} + +static inline void +istgt_iscsi_copy_pdu(ISCSI_PDU_Ptr dst_pdu, ISCSI_PDU_Ptr src_pdu) +{ + memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN); + dst_pdu->ahs = src_pdu->ahs; + dst_pdu->header_digestX = src_pdu->header_digestX; + dst_pdu->data = src_pdu->data; + dst_pdu->data_digestX = src_pdu->data_digestX; + dst_pdu->total_ahs_len = src_pdu->total_ahs_len; + dst_pdu->data_segment_len = src_pdu->data_segment_len; + dst_pdu->opcode = src_pdu->opcode; + dst_pdu->start = src_pdu->start; + src_pdu->ahs = NULL; + src_pdu->data = NULL; + src_pdu->data_segment_len = 0; + return; +} + +typedef struct iscsi_param_table_t +{ + const char *key; + const char *val; + const char *list; + int type; +} ISCSI_PARAM_TABLE; + +static ISCSI_PARAM_TABLE conn_param_table[] = +{ + { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST }, + { "DataDigest", "None", "CRC32C,None", ISPT_LIST }, + { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL }, + { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, + { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, + { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL }, + { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL }, + { "AuthMethod", "None", "CHAP,None", ISPT_LIST }, + { "CHAP_A", "5", "5", ISPT_LIST }, + { "CHAP_N", "", "", ISPT_DECLARATIVE }, + { "CHAP_R", "", "", ISPT_DECLARATIVE }, + { "CHAP_I", "", "", ISPT_DECLARATIVE }, + { "CHAP_C", "", "", ISPT_DECLARATIVE }, + { NULL, NULL, NULL, ISPT_INVALID }, +}; + +static ISCSI_PARAM_TABLE sess_param_table[] = +{ + { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL }, +#if 0 + /* need special handling */ + { "SendTargets", "", "", ISPT_DECLARATIVE }, +#endif + { "TargetName", "", "", ISPT_DECLARATIVE }, + { "InitiatorName", "", "", ISPT_DECLARATIVE }, + { "TargetAlias", "", "", ISPT_DECLARATIVE }, + { "InitiatorAlias", "", "", ISPT_DECLARATIVE }, + { "TargetAddress", "", "", ISPT_DECLARATIVE }, + { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL }, + { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, + { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND }, + { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL }, + { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL }, + { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX }, + { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL }, + { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL }, + { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, + { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, + { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL }, + { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE }, + { NULL, NULL, NULL, ISPT_INVALID }, +}; + +static int +istgt_iscsi_params_init_internal(ISCSI_PARAM **params, ISCSI_PARAM_TABLE *table) +{ + int rc; + int i; + + for (i = 0; table[i].key != NULL; i++) { + rc = istgt_iscsi_param_add(params, table[i].key, table[i].val, + table[i].list, table[i].type); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + return -1; + } + } + + return 0; +} + +static int +istgt_iscsi_conn_params_init(ISCSI_PARAM **params) +{ + return istgt_iscsi_params_init_internal(params, &conn_param_table[0]); +} + +static int +istgt_iscsi_sess_params_init(ISCSI_PARAM **params) +{ + return istgt_iscsi_params_init_internal(params, &sess_param_table[0]); +} + +static char * +istgt_iscsi_param_get_val(ISCSI_PARAM *params, const char *key) +{ + ISCSI_PARAM *param; + + param = istgt_iscsi_param_find(params, key); + if (param == NULL) + return NULL; + return param->val; +} + +static int +istgt_iscsi_param_eq_val(ISCSI_PARAM *params, const char *key, const char *val) +{ + ISCSI_PARAM *param; + + param = istgt_iscsi_param_find(params, key); + if (param == NULL) + return 0; + if (strcasecmp(param->val, val) == 0) + return 1; + return 0; +} + +#if 0 +static int +istgt_iscsi_print_params(ISCSI_PARAM *params) +{ + ISCSI_PARAM *param; + + for (param = params; param != NULL; param = param->next) { + printf("key=[%s] val=[%s] list=[%s] type=%d\n", + param->key, param->val, param->list, param->type); + } + return 0; +} +#endif + +static int +istgt_iscsi_negotiate_params(CONN_Ptr conn, ISCSI_PARAM *params, uint8_t *data, int alloc_len, int data_len) +{ + ISCSI_PARAM *param; + ISCSI_PARAM *cur_param; + char *valid_list, *in_val; + char *valid_next, *in_next; + char *cur_val; + char *new_val; + char *valid_val; + char *min_val, *max_val; + int discovery; + int cur_type; + int val_i, cur_val_i; + int min_i, max_i; + int total; + int len; + int sw; + + total = data_len; + if (alloc_len < 1) { + return 0; + } + if (total > alloc_len) { + total = alloc_len; + data[total - 1] = '\0'; + return total; + } + + if (params == NULL) { + /* no input */ + return total; + } + + /* discovery? */ + discovery = 0; + cur_param = istgt_iscsi_param_find(params, "SessionType"); + if (cur_param == NULL) { + SESS_MTX_LOCK(conn); + cur_param = istgt_iscsi_param_find(conn->sess->params, "SessionType"); + if (cur_param == NULL) { + /* no session type */ + } else { + if (strcasecmp(cur_param->val, "Discovery") == 0) { + discovery = 1; + } + } + SESS_MTX_UNLOCK(conn); + } else { + if (strcasecmp(cur_param->val, "Discovery") == 0) { + discovery = 1; + } + } + + /* for temporary store */ + valid_list = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1); + in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1); + cur_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1); + + for (param = params; param != NULL; param = param->next) { + /* sendtargets is special */ + if (strcasecmp(param->key, "SendTargets") == 0) { + continue; + } + /* CHAP keys */ + if (strcasecmp(param->key, "CHAP_A") == 0 + || strcasecmp(param->key, "CHAP_N") == 0 + || strcasecmp(param->key, "CHAP_R") == 0 + || strcasecmp(param->key, "CHAP_I") == 0 + || strcasecmp(param->key, "CHAP_C") == 0) { + continue; + } + + if (discovery) { + /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ + if (strcasecmp(param->key, "MaxConnections") == 0 + || strcasecmp(param->key, "InitialR2T") == 0 + || strcasecmp(param->key, "ImmediateData") == 0 + || strcasecmp(param->key, "MaxBurstLength") == 0 + || strcasecmp(param->key, "FirstBurstLength") == 0 + || strcasecmp(param->key, "MaxOutstandingR2T") == 0 + || strcasecmp(param->key, "DataPDUInOrder") == 0 + || strcasecmp(param->key, "DataSequenceInOrder") == 0) { + strlcpy(in_val, "Irrelevant", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + cur_type = -1; + goto add_val; + } + } + + /* get current param */ + sw = 0; + cur_param = istgt_iscsi_param_find(conn->params, param->key); + if (cur_param == NULL) { + sw = 1; + SESS_MTX_LOCK(conn); + cur_param = istgt_iscsi_param_find(conn->sess->params, + param->key); + if (cur_param == NULL) { + SESS_MTX_UNLOCK(conn); + if (strncasecmp(param->key, "X-", 2) == 0 + || strncasecmp(param->key, "X#", 2) == 0) { + /* Extension Key */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "extension key %.64s\n", + param->key); + } else { + ISTGT_ERRLOG("unknown key %.64s\n", + param->key); + } + strlcpy(in_val, "NotUnderstood", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + cur_type = -1; + goto add_val; + } + strlcpy(valid_list, cur_param->list, + ISCSI_TEXT_MAX_VAL_LEN); + strlcpy(cur_val, cur_param->val, + ISCSI_TEXT_MAX_VAL_LEN); + cur_type = cur_param->type; + SESS_MTX_UNLOCK(conn); + } else { + strlcpy(valid_list, cur_param->list, + ISCSI_TEXT_MAX_VAL_LEN); + strlcpy(cur_val, cur_param->val, + ISCSI_TEXT_MAX_VAL_LEN); + cur_type = cur_param->type; + } + + /* negotiate value */ + switch (cur_type) { + case ISPT_LIST: + strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN); + in_next = in_val; + while ((new_val = strsepq(&in_next, ",")) != NULL) { + valid_next = valid_list; + while ((valid_val = strsepq(&valid_next, ",")) != NULL) { + if (strcasecmp(new_val, valid_val) == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "match %s\n", + new_val); + goto update_val; + } + } + } + if (new_val == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "key %.64s reject\n", + param->key); + strlcpy(in_val, "Reject", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + goto add_val; + } + break; + + case ISPT_NUMERICAL: + val_i = (int) strtol(param->val, NULL, 10); + cur_val_i = (int) strtol(cur_val, NULL, 10); + valid_next = valid_list; + min_val = strsepq(&valid_next, ","); + max_val = strsepq(&valid_next, ","); + if (min_val != NULL) { + min_i = (int) strtol(min_val, NULL, 10); + } else { + min_i = 0; + } + if (max_val != NULL) { + max_i = (int) strtol(max_val, NULL, 10); + } else { + max_i = 0; + } + if (val_i < min_i || val_i > max_i) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "key %.64s reject\n", + param->key); + strlcpy(in_val, "Reject", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + goto add_val; + } + if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) { + /* Declarative, but set as same value */ + cur_val_i = conn->TargetMaxRecvDataSegmentLength; + } + if (val_i > cur_val_i) { + val_i = cur_val_i; + } + snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); + new_val = in_val; + break; + + case ISPT_NUMERICAL_MAX: + val_i = (int) strtol(param->val, NULL, 10); + cur_val_i = (int) strtol(cur_val, NULL, 10); + valid_next = valid_list; + min_val = strsepq(&valid_next, ","); + max_val = strsepq(&valid_next, ","); + if (min_val != NULL) { + min_i = (int) strtol(min_val, NULL, 10); + } else { + min_i = 0; + } + if (max_val != NULL) { + max_i = (int) strtol(max_val, NULL, 10); + } else { + max_i = 0; + } + if (val_i < min_i || val_i > max_i) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "key %.64s reject\n", + param->key); + strlcpy(in_val, "Reject", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + goto add_val; + } + if (val_i < cur_val_i) { + val_i = cur_val_i; + } + snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); + new_val = in_val; + break; + + case ISPT_BOOLEAN_OR: + if (strcasecmp(cur_val, "Yes") == 0) { + /* YES || XXX */ + strlcpy(in_val, "Yes", ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + } else { + if (strcasecmp(param->val, "Yes") == 0 + || strcasecmp(param->val, "No") == 0) { + new_val = param->val; + } else { + /* unknown value */ + strlcpy(in_val, "Reject", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + goto add_val; + } + } + break; + + case ISPT_BOOLEAN_AND: + if (strcasecmp(cur_val, "No") == 0) { + /* No && XXX */ + strlcpy(in_val, "No", ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + } else { + if (strcasecmp(param->val, "Yes") == 0 + || strcasecmp(param->val, "No") == 0) { + new_val = param->val; + } else { + /* unknown value */ + strlcpy(in_val, "Reject", + ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + goto add_val; + } + } + break; + + case ISPT_DECLARATIVE: + strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + break; + + default: + strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + break; + } + + update_val: + if (sw) { + /* update session wide */ + SESS_MTX_LOCK(conn); + istgt_iscsi_param_set(conn->sess->params, param->key, + new_val); + SESS_MTX_UNLOCK(conn); + } else { + /* update connection only */ + istgt_iscsi_param_set(conn->params, param->key, + new_val); + } + add_val: + if (cur_type != ISPT_DECLARATIVE) { + if (alloc_len - total < 1) { + ISTGT_ERRLOG("data space small %d\n", + alloc_len); + return total; + } + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "negotiated %s=%s\n", + param->key, new_val); + len = snprintf((char *) data + total, + alloc_len - total, "%s=%s", + param->key, new_val); + total += len + 1; + } + } + + xfree(valid_list); + xfree(in_val); + xfree(cur_val); + + return total; +} + +static int +istgt_iscsi_append_text(CONN_Ptr conn __attribute__((__unused__)), const char *key, const char *val, uint8_t *data, int alloc_len, int data_len) +{ + int total; + int len; + + total = data_len; + if (alloc_len < 1) { + return 0; + } + if (total > alloc_len) { + total = alloc_len; + data[total - 1] = '\0'; + return total; + } + + if (alloc_len - total < 1) { + ISTGT_ERRLOG("data space small %d\n", alloc_len); + return total; + } + len = snprintf((char *) data + total, alloc_len - total, "%s=%s", + key, val); + total += len + 1; + + return total; +} + +static int +istgt_iscsi_append_param(CONN_Ptr conn, const char *key, uint8_t *data, int alloc_len, int data_len) +{ + ISCSI_PARAM *param; + int rc; + + param = istgt_iscsi_param_find(conn->params, key); + if (param == NULL) { + param = istgt_iscsi_param_find(conn->sess->params, key); + if (param == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %.64s\n", + key); + return data_len; + } + } + rc = istgt_iscsi_append_text(conn, param->key, param->val, data, + alloc_len, data_len); + return rc; +} + +int +istgt_chap_get_authinfo(ISTGT_CHAP_AUTH *auth, const char *authfile, const char *authuser, int ag_tag) +{ + CONFIG *config = NULL; + CF_SECTION *sp; + const char *val; + const char *user, *muser; + const char *secret, *msecret; + int rc; + int i; + + if (auth->user != NULL) { + xfree(auth->user); + xfree(auth->secret); + xfree(auth->muser); + xfree(auth->msecret); + auth->user = auth->secret = NULL; + auth->muser = auth->msecret = NULL; + } + + /* read config files */ + config = istgt_allocate_config(); + rc = istgt_read_config(config, authfile); + if (rc < 0) { + ISTGT_ERRLOG("auth conf error\n"); + istgt_free_config(config); + return -1; + } + //istgt_print_config(config); + + sp = config->section; + while (sp != NULL) { + if (sp->type == ST_AUTHGROUP) { + if (sp->num == 0) { + ISTGT_ERRLOG("Group 0 is invalid\n"); + istgt_free_config(config); + return -1; + } + if (ag_tag != sp->num) { + goto skip_ag_tag; + } + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Comment %s\n", val); + } + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "Auth", i); + if (val == NULL) + break; + user = istgt_get_nmval(sp, "Auth", i, 0); + secret = istgt_get_nmval(sp, "Auth", i, 1); + muser = istgt_get_nmval(sp, "Auth", i, 2); + msecret = istgt_get_nmval(sp, "Auth", i, 3); + if (strcasecmp(authuser, user) == 0) { + /* match user */ + auth->user = xstrdup(user); + auth->secret = xstrdup(secret); + auth->muser = xstrdup(muser); + auth->msecret = xstrdup(msecret); + istgt_free_config(config); + return 0; + } + } + } + skip_ag_tag: + sp = sp->next; + } + + istgt_free_config(config); + return 0; +} + +static int +istgt_iscsi_get_authinfo(CONN_Ptr conn, const char *authuser) +{ + char *authfile = NULL; + int ag_tag; + int rc; + + SESS_MTX_LOCK(conn); + if (conn->sess->lu != NULL) { + ag_tag = conn->sess->lu->auth_group; + } else { + ag_tag = -1; + } + SESS_MTX_UNLOCK(conn); + if (ag_tag < 0) { + MTX_LOCK(&conn->istgt->mutex); + ag_tag = conn->istgt->discovery_auth_group; + MTX_UNLOCK(&conn->istgt->mutex); + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ag_tag=%d\n", ag_tag); + + MTX_LOCK(&conn->istgt->mutex); + authfile = xstrdup(conn->istgt->authfile); + MTX_UNLOCK(&conn->istgt->mutex); + + rc = istgt_chap_get_authinfo(&conn->auth, authfile, authuser, ag_tag); + if (rc < 0) { + ISTGT_ERRLOG("chap_get_authinfo() failed\n"); + xfree(authfile); + return -1; + } + xfree(authfile); + return 0; +} + +static int +istgt_iscsi_auth_params(CONN_Ptr conn, ISCSI_PARAM *params, const char *method, uint8_t *data, int alloc_len, int data_len) +{ + char *in_val; + char *in_next; + char *new_val; + const char *val; + const char *user; + const char *response; + const char *challenge; + int total; + int rc; + + if (conn == NULL || params == NULL || method == NULL) { + return -1; + } + if (strcasecmp(method, "CHAP") == 0) { + /* method OK */ + } else { + ISTGT_ERRLOG("unsupported AuthMethod %.64s\n", method); + return -1; + } + + total = data_len; + if (alloc_len < 1) { + return 0; + } + if (total > alloc_len) { + total = alloc_len; + data[total - 1] = '\0'; + return total; + } + + /* for temporary store */ + in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1); + + /* CHAP method (RFC1994) */ + if ((val = ISCSI_GETVAL(params, "CHAP_A")) != NULL) { + if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_A) { + ISTGT_ERRLOG("CHAP sequence error\n"); + goto error_return; + } + + /* CHAP_A is LIST type */ + strlcpy(in_val, val, ISCSI_TEXT_MAX_VAL_LEN); + in_next = in_val; + while ((new_val = strsepq(&in_next, ",")) != NULL) { + if (strcasecmp(new_val, "5") == 0) { + /* CHAP with MD5 */ + break; + } + } + if (new_val == NULL) { + strlcpy(in_val, "Reject", ISCSI_TEXT_MAX_VAL_LEN); + new_val = in_val; + total = istgt_iscsi_append_text(conn, "CHAP_A", + new_val, data, alloc_len, total); + goto error_return; + } + /* selected algorithm is 5 (MD5) */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_A=%s\n", new_val); + total = istgt_iscsi_append_text(conn, "CHAP_A", new_val, + data, alloc_len, total); + + /* Identifier is one octet */ + istgt_gen_random(conn->auth.chap_id, 1); + snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", + (int) conn->auth.chap_id[0]); + total = istgt_iscsi_append_text(conn, "CHAP_I", in_val, + data, alloc_len, total); + + /* Challenge Value is a variable stream of octets */ + /* (binary length MUST not exceed 1024 bytes) */ + conn->auth.chap_challenge_len = ISTGT_CHAP_CHALLENGE_LEN; + istgt_gen_random(conn->auth.chap_challenge, + conn->auth.chap_challenge_len); + istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, + conn->auth.chap_challenge, + conn->auth.chap_challenge_len); + total = istgt_iscsi_append_text(conn, "CHAP_C", in_val, + data, alloc_len, total); + + conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_NR; + } else if ((val = ISCSI_GETVAL(params, "CHAP_N")) != NULL) { + uint8_t resmd5[ISTGT_MD5DIGEST_LEN]; + uint8_t tgtmd5[ISTGT_MD5DIGEST_LEN]; + ISTGT_MD5CTX md5ctx; + + user = val; + if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_NR) { + ISTGT_ERRLOG("CHAP sequence error\n"); + goto error_return; + } + + response = ISCSI_GETVAL(params, "CHAP_R"); + if (response == NULL) { + ISTGT_ERRLOG("no response\n"); + goto error_return; + } + rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, response); + if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) { + ISTGT_ERRLOG("response format error\n"); + goto error_return; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_N/CHAP_R\n"); + + rc = istgt_iscsi_get_authinfo(conn, val); + if (rc < 0) { + //ISTGT_ERRLOG("auth user or secret is missing\n"); + ISTGT_ERRLOG("iscsi_get_authinfo() failed\n"); + goto error_return; + } + if (conn->auth.user == NULL || conn->auth.secret == NULL) { + //ISTGT_ERRLOG("auth user or secret is missing\n"); + ISTGT_ERRLOG("auth failed (user %.64s)\n", user); + goto error_return; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, conn->auth.chap_id, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, conn->auth.secret, + strlen(conn->auth.secret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, conn->auth.chap_challenge, + conn->auth.chap_challenge_len); + /* tgtmd5 is expecting Response Value */ + istgt_md5final(tgtmd5, &md5ctx); + + istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, + tgtmd5, ISTGT_MD5DIGEST_LEN); + +#if 0 + printf("tgtmd5=%s, resmd5=%s\n", in_val, response); + istgt_dump("tgtmd5", tgtmd5, ISTGT_MD5DIGEST_LEN); + istgt_dump("resmd5", resmd5, ISTGT_MD5DIGEST_LEN); +#endif + + /* compare MD5 digest */ + if (memcmp(tgtmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) { + /* not match */ + //ISTGT_ERRLOG("auth user or secret is missing\n"); + ISTGT_ERRLOG("auth failed (user %.64s)\n", user); + goto error_return; + } + /* OK initiator's secret */ + conn->authenticated = 1; + + /* mutual CHAP? */ + val = ISCSI_GETVAL(params, "CHAP_I"); + if (val != NULL) { + conn->auth.chap_mid[0] = (uint8_t) strtol(val, NULL, 10); + challenge = ISCSI_GETVAL(params, "CHAP_C"); + if (challenge == NULL) { + ISTGT_ERRLOG("CHAP sequence error\n"); + goto error_return; + } + rc = istgt_hex2bin(conn->auth.chap_mchallenge, + ISTGT_CHAP_CHALLENGE_LEN, + challenge); + if (rc < 0) { + ISTGT_ERRLOG("challenge format error\n"); + goto error_return; + } + conn->auth.chap_mchallenge_len = rc; +#if 0 + istgt_dump("MChallenge", conn->auth.chap_mchallenge, + conn->auth.chap_mchallenge_len); +#endif + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "got CHAP_I/CHAP_C\n"); + + if (conn->auth.muser == NULL || conn->auth.msecret == NULL) { + //ISTGT_ERRLOG("mutual auth user or secret is missing\n"); + ISTGT_ERRLOG("auth failed (user %.64s)\n", + user); + goto error_return; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, conn->auth.chap_mid, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, conn->auth.msecret, + strlen(conn->auth.msecret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, conn->auth.chap_mchallenge, + conn->auth.chap_mchallenge_len); + /* tgtmd5 is Response Value */ + istgt_md5final(tgtmd5, &md5ctx); + + istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN, + tgtmd5, ISTGT_MD5DIGEST_LEN); + + total = istgt_iscsi_append_text(conn, "CHAP_N", + conn->auth.muser, data, alloc_len, total); + total = istgt_iscsi_append_text(conn, "CHAP_R", + in_val, data, alloc_len, total); + } else { + /* not mutual */ + if (conn->req_mutual) { + ISTGT_ERRLOG("required mutual CHAP\n"); + goto error_return; + } + } + + conn->auth.chap_phase = ISTGT_CHAP_PHASE_END; + } else { + /* not found CHAP keys */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "start CHAP\n"); + conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A; + } + + xfree(in_val); + return total; + + error_return: + conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A; + xfree(in_val); + return -1; +} + +static int +istgt_iscsi_reject(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int reason) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *data; + int total_ahs_len; + int data_len; + int alloc_len; + int rc; + uint32_t l_SSN = conn->StatSN, l_CSN = 0, l_MCSN = 0; + + total_ahs_len = DGET8(&pdu->bhs.total_ahs_len); + data_len = 0; + alloc_len = ISCSI_BHS_LEN + (4 * total_ahs_len); + if (conn->header_digest) { + alloc_len += ISCSI_DIGEST_LEN; + } + data = xmalloc(alloc_len); + memset(data, 0, alloc_len); + + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + l_CSN = conn->sess->ExpCmdSN; + l_MCSN = conn->sess->MaxCmdSN; + SESS_MTX_UNLOCK(conn); + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "Reject PDU reason=%d StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x\n", + reason, l_SSN, l_CSN, l_MCSN); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "Reject PDU reason=%d StatSN=%x\n", + reason, conn->StatSN); + } + + memcpy(data, &pdu->bhs, ISCSI_BHS_LEN); + data_len += ISCSI_BHS_LEN; + if (total_ahs_len != 0) { + memcpy(data + data_len, pdu->ahs, (4 * total_ahs_len)); + data_len += (4 * total_ahs_len); + } + if (conn->header_digest) { + memcpy(data + data_len, pdu->header_digest, ISCSI_DIGEST_LEN); + data_len += ISCSI_DIGEST_LEN; + } + + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = data; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_REJECT; + BDADD8W(&rsp[1], 1, 7, 1); + rsp[2] = reason; + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], data_len); // DataSegmentLength + + DSET32(&rsp[16], 0xffffffffU); + + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + } else { + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + DSET32(&rsp[28], 1); + DSET32(&rsp[32], 1); + } + DSET32(&rsp[36], 0); // DataSN/R2TSN + + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN); + + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + + return 0; +} + +static void +istgt_iscsi_copy_param2var(CONN_Ptr conn) +{ + const char *val; + + val = ISCSI_GETVAL(conn->params, "MaxRecvDataSegmentLength"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "copy MaxRecvDataSegmentLength=%s\n", val); + conn->MaxRecvDataSegmentLength = (int) strtol(val, NULL, 10); + if (conn->sendbufsize != conn->MaxRecvDataSegmentLength) { + xfree(conn->recvbuf); + xfree(conn->sendbuf); + if (conn->MaxRecvDataSegmentLength < 8192) { + conn->recvbufsize = 8192; + conn->sendbufsize = 8192; + } else { + conn->recvbufsize = conn->MaxRecvDataSegmentLength; + conn->sendbufsize = conn->MaxRecvDataSegmentLength; + } + conn->recvbuf = xmalloc(conn->recvbufsize); + conn->sendbuf = xmalloc(conn->sendbufsize); + } + val = ISCSI_GETVAL(conn->params, "HeaderDigest"); + if (strcasecmp(val, "CRC32C") == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=1\n"); + conn->header_digest = 1; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=0\n"); + conn->header_digest = 0; + } + val = ISCSI_GETVAL(conn->params, "DataDigest"); + if (strcasecmp(val, "CRC32C") == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=1\n"); + conn->data_digest = 1; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=0\n"); + conn->data_digest = 0; + } + + SESS_MTX_LOCK(conn); + val = ISCSI_GETVAL(conn->sess->params, "MaxConnections"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxConnections=%s\n", val); + conn->sess->MaxConnections = (int) strtol(val, NULL, 10); + val = ISCSI_GETVAL(conn->sess->params, "MaxOutstandingR2T"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxOutstandingR2T=%s\n", val); + conn->sess->MaxOutstandingR2T = (int) strtol(val, NULL, 10); + conn->MaxOutstandingR2T = conn->sess->MaxOutstandingR2T; + val = ISCSI_GETVAL(conn->sess->params, "FirstBurstLength"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy FirstBurstLength=%s\n", val); + conn->sess->FirstBurstLength = (int) strtol(val, NULL, 10); + conn->FirstBurstLength = conn->sess->FirstBurstLength; + val = ISCSI_GETVAL(conn->sess->params, "MaxBurstLength"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxBurstLength=%s\n", val); + conn->sess->MaxBurstLength = (int) strtol(val, NULL, 10); + conn->MaxBurstLength = conn->sess->MaxBurstLength; + val = ISCSI_GETVAL(conn->sess->params, "InitialR2T"); + if (strcasecmp(val, "Yes") == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=1\n"); + conn->sess->initial_r2t = 1; + } else{ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=0\n"); + conn->sess->initial_r2t = 0; + } + val = ISCSI_GETVAL(conn->sess->params, "ImmediateData"); + if (strcasecmp(val, "Yes") == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=1\n"); + conn->sess->immediate_data = 1; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=0\n"); + conn->sess->immediate_data = 0; + } + SESS_MTX_UNLOCK(conn); +} + +static int +istgt_iscsi_check_values(CONN_Ptr conn) +{ + SESS_MTX_LOCK(conn); + if (conn->sess->FirstBurstLength > conn->sess->MaxBurstLength) { + ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n", + conn->sess->FirstBurstLength, + conn->sess->MaxBurstLength); + SESS_MTX_UNLOCK(conn); + return -1; + } + if (conn->sess->MaxBurstLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", + conn->sess->MaxBurstLength); + SESS_MTX_UNLOCK(conn); + return -1; + } + if (conn->TargetMaxRecvDataSegmentLength < 512) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n", + conn->TargetMaxRecvDataSegmentLength); + return -1; + } + if (conn->TargetMaxRecvDataSegmentLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n", + conn->TargetMaxRecvDataSegmentLength); + SESS_MTX_UNLOCK(conn); + return -1; + } + if (conn->MaxRecvDataSegmentLength < 512) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n", + conn->MaxRecvDataSegmentLength); + return -1; + } + if (conn->MaxRecvDataSegmentLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n", + conn->MaxRecvDataSegmentLength); + SESS_MTX_UNLOCK(conn); + return -1; + } + SESS_MTX_UNLOCK(conn); + return 0; +} + +static int +istgt_iscsi_op_login(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + char buf[MAX_TMPBUF]; + ISTGT_LU_Ptr lu = NULL; + ISCSI_PARAM *params = NULL; + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + uint8_t *data; + const char *session_type; + const char *auth_method; + const char *val; + uint64_t isid; + uint16_t tsih; + uint16_t cid; + uint32_t task_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + int T_bit, C_bit; + int CSG, NSG; + int VersionMin, VersionMax; + int StatusClass, StatusDetail; + int data_len; + int alloc_len; + int rc; + + /* Login is proceeding OK */ + StatusClass = 0x00; + StatusDetail = 0x00; + + data_len = 0; + + if (conn->MaxRecvDataSegmentLength < 8192) { + // Default MaxRecvDataSegmentLength - RFC3720(12.12) + alloc_len = 8192; + } else { + alloc_len = conn->MaxRecvDataSegmentLength; + } + data = xmalloc(alloc_len); + memset(data, 0, alloc_len); + + cp = (uint8_t *) &pdu->bhs; + T_bit = BGET8(&cp[1], 7); + C_bit = BGET8(&cp[1], 6); + CSG = BGET8W(&cp[1], 3, 2); + NSG = BGET8W(&cp[1], 1, 2); + VersionMin = cp[2]; + VersionMax = cp[3]; + + isid = DGET48(&cp[8]); + tsih = DGET16(&cp[14]); + cid = DGET16(&cp[20]); + task_tag = DGET32(&cp[16]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + +#if 0 + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN); +#endif + + if (conn->sess != NULL) { + //SESS_MTX_LOCK(conn); + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "op_login CSN:%x T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x ExpStatSN=%x, StatSN=%x (session)\n", + CmdSN, T_bit, C_bit, CSG, NSG, VersionMin, VersionMax, task_tag, + ExpStatSN, conn->StatSN); //, conn->sess->ExpCmdSN, conn->sess->MaxCmdSN); + //SESS_MTX_UNLOCK(conn); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "op_login CSN:%x T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x ExpStatSN=%x, StatSN=%x\n", + CmdSN, T_bit, C_bit, CSG, NSG, VersionMin, VersionMax, task_tag, + ExpStatSN, conn->StatSN); + } + + if (T_bit && C_bit) { + ISTGT_ERRLOG("transit error\n"); + xfree(data); + return -1; + } + if (VersionMin > ISCSI_VERSION || VersionMax < ISCSI_VERSION) { + ISTGT_ERRLOG("unsupported version %d/%d\n", VersionMin, VersionMax); + /* Unsupported version */ + StatusClass = 0x02; + StatusDetail = 0x05; + goto response; + } + + /* store incoming parameters */ + rc = istgt_iscsi_parse_params(¶ms, pdu->data, pdu->data_segment_len); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_parse_params() failed\n"); + error_return: + istgt_iscsi_param_free(params); + xfree(data); + return -1; + } + + /* set port identifiers and parameters */ + if (conn->login_phase == ISCSI_LOGIN_PHASE_NONE) { + /* Initiator Name and Port */ + val = ISCSI_GETVAL(params, "InitiatorName"); + if (val == NULL) { + ISTGT_ERRLOG("InitiatorName is empty\n"); + /* Missing parameter */ + StatusClass = 0x02; + StatusDetail = 0x07; + goto response; + } + snprintf(conn->initiator_name, sizeof conn->initiator_name, + "%s", val); + snprintf(conn->initiator_port, sizeof conn->initiator_port, + "%s" ",i,0x" "%12.12" PRIx64, val, isid); + /* + * We did this because of some normalization issue. + * But need to comment out this for logging issue. + * May be another solution will be needed in future if + * normalization is mandatory. + */ + strlwr(conn->initiator_name); + strlwr(conn->initiator_port); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator name: %s\n", + conn->initiator_name); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator port: %s\n", + conn->initiator_port); + + /* Session Type */ + session_type = ISCSI_GETVAL(params, "SessionType"); + if (session_type == NULL) { + if (tsih != 0) { + session_type = "Normal"; + } else { + ISTGT_ERRLOG("SessionType is empty\n"); + /* Missing parameter */ + StatusClass = 0x02; + StatusDetail = 0x07; + goto response; + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Session Type: %s\n", + session_type); + + /* Target Name and Port */ + if (strcasecmp(session_type, "Normal") == 0) { + val = ISCSI_GETVAL(params, "TargetName"); + if (val == NULL) { + ISTGT_ERRLOG("TargetName is empty\n"); + /* Missing parameter */ + StatusClass = 0x02; + StatusDetail = 0x07; + goto response; + } + snprintf(conn->target_name, sizeof conn->target_name, + "%s", val); + snprintf(conn->target_port, sizeof conn->target_port, + "%s" ",t,0x" "%4.4x", val, conn->portal.tag); + strlwr(conn->target_name); + strlwr(conn->target_port); + + MTX_LOCK(&conn->istgt->mutex); + lu = istgt_lu_find_target(conn->istgt, + conn->target_name); + if (lu == NULL) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("lu_find_target() failed\n"); + /* Not found */ + StatusClass = 0x02; + StatusDetail = 0x03; + goto response; + } + rc = istgt_lu_access(conn, lu, conn->initiator_name, + conn->initiator_addr); + if (rc < 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("lu_access() failed\n"); + /* Not found */ + StatusClass = 0x02; + StatusDetail = 0x03; + goto response; + } + if (rc == 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("access denied\n"); + /* Not found */ + StatusClass = 0x02; + StatusDetail = 0x03; + goto response; + } + MTX_UNLOCK(&conn->istgt->mutex); + + /* check existing session */ + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "isid=%"PRIx64", tsih=%u, cid=%u\n", + isid, tsih, cid); + if (tsih != 0) { + /* multiple connections */ + rc = istgt_append_sess(conn, isid, tsih, cid); + if (rc < 0) { + ISTGT_ERRLOG("isid=%"PRIx64", tsih=%u, cid=%u: " + "append_sess() failed\n", + isid, tsih, cid); + /* Can't include in session */ + StatusClass = 0x02; + StatusDetail = 0x08; + goto response; + } + } else { + /* new session, drop old sess by the initiator */ + istgt_iscsi_drop_old_conns(conn); + } + + /* force target flags */ + MTX_LOCK(&lu->mutex); + if (lu->no_auth_chap) { + conn->req_auth = 0; + rc = istgt_iscsi_param_del(&conn->params, + "AuthMethod"); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "AuthMethod", "None", "None", ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } else if (lu->auth_chap) { + conn->req_auth = 1; + rc = istgt_iscsi_param_del(&conn->params, + "AuthMethod"); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "AuthMethod", "CHAP", "CHAP", ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } + if (lu->auth_chap_mutual) { + conn->req_mutual = 1; + } + if (lu->header_digest) { + rc = istgt_iscsi_param_del(&conn->params, + "HeaderDigest"); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "HeaderDigest", "CRC32C", "CRC32C", + ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } + if (lu->data_digest) { + rc = istgt_iscsi_param_del(&conn->params, + "DataDigest"); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "DataDigest", "CRC32C", "CRC32C", + ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&lu->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } + MTX_UNLOCK(&lu->mutex); + } else if (strcasecmp(session_type, "Discovery") == 0) { + snprintf(conn->target_name, sizeof conn->target_name, + "%s", "dummy"); + snprintf(conn->target_port, sizeof conn->target_port, + "%s" ",t,0x" "%4.4x", "dummy", conn->portal.tag); + lu = NULL; + tsih = 0; + + /* force target flags */ + MTX_LOCK(&conn->istgt->mutex); + if (conn->istgt->no_discovery_auth) { + conn->req_auth = 0; + rc = istgt_iscsi_param_del(&conn->params, + "AuthMethod"); + if (rc < 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "AuthMethod", "None", "None", ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } else if (conn->istgt->req_discovery_auth) { + conn->req_auth = 1; + rc = istgt_iscsi_param_del(&conn->params, + "AuthMethod"); + if (rc < 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("iscsi_param_del() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_add(&conn->params, + "AuthMethod", "CHAP", "CHAP", ISPT_LIST); + if (rc < 0) { + MTX_UNLOCK(&conn->istgt->mutex); + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + } + if (conn->istgt->req_discovery_auth_mutual) { + conn->req_mutual = 1; + } + MTX_UNLOCK(&conn->istgt->mutex); + } else { + ISTGT_ERRLOG("unknown session type\n"); + /* Missing parameter */ + StatusClass = 0x02; + StatusDetail = 0x07; + goto response; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target name: %s\n", + conn->target_name); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target port: %s\n", + conn->target_port); + + conn->authenticated = 0; + conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A; + conn->cid = cid; + if (lu == NULL || lu->queue_depth == 0) { + conn->queue_depth = ISCMDQ; + } else { + conn->queue_depth = lu->queue_depth; + } + conn->max_pending = (conn->queue_depth + 1) * 2; +#if 0 + /* override config setting */ + MTX_LOCK(&conn->r2t_mutex); + if ((conn->max_r2t > 0) + && (conn->max_r2t < conn->max_pending)) { + int i; + xfree(conn->r2t_tasks); + conn->max_r2t = conn->max_pending; + conn->r2t_tasks = xmalloc (sizeof *conn->r2t_tasks + * (conn->max_r2t + 1)); + for (i = 0; i < (conn->max_r2t + 1); i++) { + conn->r2t_tasks[i] = NULL; + } + } + MTX_UNLOCK(&conn->r2t_mutex); +#endif + if (conn->sess == NULL) { + /* new session */ + rc = istgt_create_sess(conn->istgt, conn, lu); + if (rc < 0) { + ISTGT_ERRLOG("create_sess() failed\n"); + goto error_return; + } + + /* initialize parameters */ + SESS_MTX_LOCK(conn); + conn->StatSN = ExpStatSN; + conn->MaxOutstandingR2T + = conn->sess->MaxOutstandingR2T; + conn->isid = isid; + conn->tsih = tsih; + conn->sess->isid = isid; + conn->sess->tsih = tsih; + conn->sess->lu = lu; + conn->sess->ExpCmdSN = CmdSN; + conn->sess->MaxCmdSN = CmdSN + conn->queue_depth - 1; + conn->sess->MaxCmdSN_local = conn->sess->MaxCmdSN; + SESS_MTX_UNLOCK(conn); + } + + /* limit conns on discovery session */ + if (strcasecmp(session_type, "Discovery") == 0) { + SESS_MTX_LOCK(conn); + conn->sess->MaxConnections = 1; + rc = istgt_iscsi_param_set_int(conn->sess->params, + "MaxConnections", conn->sess->MaxConnections); + SESS_MTX_UNLOCK(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + } + + /* declarative parameters */ + if (lu != NULL) { + MTX_LOCK(&lu->mutex); + if (lu->alias != NULL) { + snprintf(buf, sizeof buf, "%s", lu->alias); + } else { + snprintf(buf, sizeof buf, "%s", ""); + } + MTX_UNLOCK(&lu->mutex); + SESS_MTX_LOCK(conn); + rc = istgt_iscsi_param_set(conn->sess->params, + "TargetAlias", buf); + SESS_MTX_UNLOCK(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + } + snprintf(buf, sizeof buf, "%s:%s,%d", + conn->portal.host, conn->portal.port, conn->portal.tag); + SESS_MTX_LOCK(conn); + rc = istgt_iscsi_param_set(conn->sess->params, + "TargetAddress", buf); + SESS_MTX_UNLOCK(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + snprintf(buf, sizeof buf, "%d", conn->portal.tag); + SESS_MTX_LOCK(conn); + rc = istgt_iscsi_param_set(conn->sess->params, + "TargetPortalGroupTag", buf); + SESS_MTX_UNLOCK(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + + /* write in response */ + if (lu != NULL) { + SESS_MTX_LOCK(conn); + val = ISCSI_GETVAL(conn->sess->params, "TargetAlias"); + if (val != NULL && strlen(val) != 0) { + data_len = istgt_iscsi_append_param(conn, + "TargetAlias", data, alloc_len, data_len); + } + if (strcasecmp(session_type, "Discovery") == 0) { + data_len = istgt_iscsi_append_param(conn, + "TargetAddress", data, alloc_len, data_len); + } + data_len = istgt_iscsi_append_param(conn, + "TargetPortalGroupTag", data, alloc_len, data_len); + SESS_MTX_UNLOCK(conn); + } + + /* start login phase */ + conn->login_phase = ISCSI_LOGIN_PHASE_START; + } + + /* negotiate parameters */ + data_len = istgt_iscsi_negotiate_params(conn, params, + data, alloc_len, data_len); + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params", + data, data_len); + + switch (CSG) { + case 0: + /* SecurityNegotiation */ + auth_method = ISCSI_GETVAL(conn->params, "AuthMethod"); + if (auth_method == NULL) { + ISTGT_ERRLOG("AuthMethod is empty\n"); + /* Missing parameter */ + StatusClass = 0x02; + StatusDetail = 0x07; + goto response; + } + if (strcasecmp(auth_method, "None") == 0) { + conn->authenticated = 1; + } else { + rc = istgt_iscsi_auth_params(conn, params, auth_method, + data, alloc_len, data_len); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_auth_params() failed\n"); + /* Authentication failure */ + StatusClass = 0x02; + StatusDetail = 0x01; + goto response; + } + data_len = rc; + if (conn->authenticated == 0) { + /* not complete */ + T_bit = 0; + } else { + if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_END) { + ISTGT_WARNLOG("CHAP phase not complete"); + } + } +#if 0 + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "Negotiated Auth Params", data, data_len); +#endif + } + break; + case 1: + /* LoginOperationalNegotiation */ + if (conn->login_phase == ISCSI_LOGIN_PHASE_START) { + if (conn->req_auth) { + /* Authentication failure */ + StatusClass = 0x02; + StatusDetail = 0x01; + goto response; + } else { + /* AuthMethod=None */ + conn->authenticated = 1; + } + } + if (conn->authenticated == 0) { + ISTGT_ERRLOG("authentication error\n"); + /* Authentication failure */ + StatusClass = 0x02; + StatusDetail = 0x01; + goto response; + } + break; + case 3: + /* FullFeaturePhase */ + ISTGT_ERRLOG("XXX Login in FullFeaturePhase\n"); + /* Initiator error */ + StatusClass = 0x02; + StatusDetail = 0x00; + goto response; + default: + ISTGT_ERRLOG("unknown stage\n"); + /* Initiator error */ + StatusClass = 0x02; + StatusDetail = 0x00; + goto response; + } + + if (T_bit) { + switch (NSG) { + case 0: + /* SecurityNegotiation */ + conn->login_phase = ISCSI_LOGIN_PHASE_SECURITY; + break; + case 1: + /* LoginOperationalNegotiation */ + conn->login_phase = ISCSI_LOGIN_PHASE_OPERATIONAL; + break; + case 3: + /* FullFeaturePhase */ + conn->login_phase = ISCSI_LOGIN_PHASE_FULLFEATURE; + rc = istgt_lu_add_nexus(conn->sess->lu, conn->initiator_port); + if (rc == -1) { + /* Ignore the error, Since during discovery there is no nexus formed*/ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Failed to Add the Nexus\n"); + } else if(rc == -2) { + ISTGT_ERRLOG("Failed to Add the Nexus\n"); + goto error_return; + } + + if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) { + /* normal session */ + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + tsih = conn->sess->tsih; + /* new tsih? */ + if (tsih == 0) { + tsih = istgt_lu_allocate_tsih(conn->sess->lu, + conn->initiator_port, + conn->portal.tag); + if (tsih == 0) { + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + ISTGT_ERRLOG("lu_allocate_tsih() failed\n"); + goto error_return; + } + conn->sess->tsih = tsih; + } else { + /* multiple connection */ + } + conn->sess->lu->conns++; + snprintf(buf, sizeof buf, "Login from %s (%s) on %s LU%d" + " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u," + " CID=%u, HeaderDigest=%s, DataDigest=%s\n", + conn->initiator_name, conn->initiator_addr, + conn->target_name, conn->sess->lu->num, + conn->portal.host, conn->portal.port, + conn->portal.tag, + conn->sess->isid, conn->sess->tsih, conn->cid, + (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C") + ? "on" : "off"), + (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C") + ? "on" : "off")); + ioctl_call(conn, TYPE_LOGIN); + ISTGT_NOTICELOG("%s", buf); + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + istgt_connection_status(conn, "SUCCESSFULL LOGIN"); + + } else if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Discovery")) { + /* discovery session */ + /* new tsih */ + SESS_MTX_LOCK(conn); + MTX_LOCK(&g_last_tsih_mutex); + tsih = conn->sess->tsih; + g_last_tsih++; + tsih = g_last_tsih; + if (tsih == 0) { + g_last_tsih++; + tsih = g_last_tsih; + } + conn->sess->tsih = tsih; + MTX_UNLOCK(&g_last_tsih_mutex); + + snprintf(buf, sizeof buf, "Login(discovery) from %s (%s) on" + " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u," + " CID=%u, HeaderDigest=%s, DataDigest=%s\n", + conn->initiator_name, conn->initiator_addr, + conn->portal.host, conn->portal.port, + conn->portal.tag, + conn->sess->isid, conn->sess->tsih, conn->cid, + (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C") + ? "on" : "off"), + (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C") + ? "on" : "off")); + ISTGT_NOTICELOG("%s", buf); + SESS_MTX_UNLOCK(conn); + } else { + ISTGT_ERRLOG("unknown session type\n"); + /* Initiator error */ + StatusClass = 0x02; + StatusDetail = 0x00; + goto response; + } + + conn->full_feature = 1; + break; + default: + ISTGT_ERRLOG("unknown stage\n"); + /* Initiator error */ + StatusClass = 0x02; + StatusDetail = 0x00; + goto response; + } + } + + response: + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + if(data_len == 0) { + xfree(data); + data = NULL; + } + rsp_pdu.data = data; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_LOGIN_RSP; + BDADD8(&rsp[1], T_bit, 7); + BDADD8(&rsp[1], C_bit, 6); + BDADD8W(&rsp[1], CSG, 3, 2); + BDADD8W(&rsp[1], NSG, 1, 2); + rsp[2] = ISCSI_VERSION; // Version-max + rsp[3] = ISCSI_VERSION; // Version-active + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], data_len); // DataSegmentLength + + DSET48(&rsp[8], isid); + DSET16(&rsp[14], tsih); + DSET32(&rsp[16], task_tag); + + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + } else { + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + DSET32(&rsp[28], CmdSN); + DSET32(&rsp[32], CmdSN); + } + + rsp[36] = StatusClass; + rsp[37] = StatusDetail; + +#if 0 + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN); + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DATA", data, data_len); +#endif + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + istgt_iscsi_param_free(params); + return -1; + } + + /* after send PDU digest on/off */ + if (conn->full_feature) { + /* update internal variables */ + istgt_iscsi_copy_param2var(conn); + /* check value */ + rc = istgt_iscsi_check_values(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_check_values() failed\n"); + istgt_iscsi_param_free(params); + if(data != NULL) + xfree(data); + return -1; + } + } + + istgt_iscsi_param_free(params); + return 0; +} + +static int +istgt_iscsi_op_text(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + ISCSI_PARAM *params = NULL; + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + uint8_t *data; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + const char *val; + int I_bit, F_bit, C_bit; + int data_len; + int alloc_len; + int rc; + uint32_t sExpCmdSN = 0; + uint32_t sMaxCmdSN = 0; + uint32_t cStatSN = 0; + int step = 0; + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + + data_len = 0; + alloc_len = conn->sendbufsize; + data = xmalloc(alloc_len); //(uint8_t *) conn->sendbuf; + memset(data, 0, alloc_len); + + cp = (uint8_t *) &pdu->bhs; + I_bit = BGET8(&cp[0], 7); + F_bit = BGET8(&cp[1], 7); + C_bit = BGET8(&cp[1], 6); + + lun = DGET64(&cp[8]); + task_tag = DGET32(&cp[16]); + transfer_tag = DGET32(&cp[20]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + + SESS_MTX_LOCK(conn); + sExpCmdSN = conn->sess->ExpCmdSN; + sMaxCmdSN = conn->sess->MaxCmdSN; + cStatSN = conn->StatSN; + + if (I_bit == 0) { + if (SN32_LT(CmdSN, conn->sess->ExpCmdSN) + || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) { + SESS_MTX_UNLOCK(conn); + ISTGT_ERRLOG("op_text CSN=%x ignore expCSN:%x-%x. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eSSN=%x, StatSN=%x\n", + CmdSN, sExpCmdSN, sMaxCmdSN, + I_bit, F_bit, C_bit, task_tag, transfer_tag, ExpStatSN, cStatSN); + return -1; + } + } else if (CmdSN != conn->sess->ExpCmdSN) { + SESS_MTX_UNLOCK(conn); + ISTGT_ERRLOG("op_text CSN=%x not expCSN:%x-%x. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eSSN=%x, StatSN=%x\n", + CmdSN, sExpCmdSN, sMaxCmdSN, + I_bit, F_bit, C_bit, task_tag, transfer_tag, ExpStatSN, cStatSN); + return -1; + } + if (SN32_GT(ExpStatSN, conn->StatSN)) { + step = 1; + conn->StatSN = ExpStatSN; + } + if (ExpStatSN != conn->StatSN) { + /* StarPort have a bug */ + step = 2; + conn->StatSN = ExpStatSN; + } + SESS_MTX_UNLOCK(conn); + + if (step == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "op_text CSN=%x SSN:%x-advancedto-eSSN:%x. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eCSN:%x-%x\n", + CmdSN, cStatSN, ExpStatSN, + I_bit, F_bit, C_bit, task_tag, transfer_tag, sExpCmdSN, sMaxCmdSN); + } else if (step == 2) { + ISTGT_WARNLOG("op_text CSN=%x SSN:%x-rewoundto-eSSN:%x. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eCSN:%x-%x\n", + CmdSN, cStatSN, ExpStatSN, + I_bit, F_bit, C_bit, task_tag, transfer_tag, sExpCmdSN, sMaxCmdSN); + } + + if (F_bit && C_bit) { + if (step != 2) { //we didn't log + ISTGT_ERRLOG("op_text CSN=%x final_and_continue. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eSSN=%x, StatSN=%x, eCSN=%x-%x\n", + CmdSN, I_bit, F_bit, C_bit, task_tag, transfer_tag, + ExpStatSN, cStatSN, sExpCmdSN, sMaxCmdSN); + } else { + ISTGT_ERRLOG("CSN=%x final and continue\n", CmdSN); + } + return -1; + } + + if (step == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "op_text CSN=%x final_and_continue. I=%d, F=%d, C=%d, ITT=%x, TTT=%x, eSSN=%x, StatSN=%x, eCSN=%x-%x\n", + CmdSN, I_bit, F_bit, C_bit, task_tag, transfer_tag, + ExpStatSN, cStatSN, sExpCmdSN, sMaxCmdSN); + } + + + /* store incoming parameters */ + rc = istgt_iscsi_parse_params(¶ms, pdu->data, + pdu->data_segment_len); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_parse_params() failed\n"); + istgt_iscsi_param_free(params); + return -1; + } + + /* negotiate parameters */ + data_len = istgt_iscsi_negotiate_params(conn, params, + data, alloc_len, data_len); + /* sendtargets is special case */ + val = ISCSI_GETVAL(params, "SendTargets"); + if (val != NULL) { + if (strcasecmp(val, "") == 0) { + val = conn->target_name; + } + SESS_MTX_LOCK(conn); + ISCSI_GETVAL(conn->sess->params, + "InitiatorName"); + if (ISCSI_EQVAL(conn->sess->params, + "SessionType", "Discovery")) { + SESS_MTX_UNLOCK(conn); + data_len = istgt_lu_sendtargets(conn, + conn->initiator_name, + conn->initiator_addr, + val, data, alloc_len, data_len); + SESS_MTX_LOCK(conn); + } else { + if (strcasecmp(val, "ALL") == 0) { + /* not in discovery session */ + data_len = istgt_iscsi_append_text(conn, "SendTargets", + "Reject", data, alloc_len, data_len); + } else { + SESS_MTX_UNLOCK(conn); + data_len = istgt_lu_sendtargets(conn, + conn->initiator_name, + conn->initiator_addr, + val, data, alloc_len, data_len); + SESS_MTX_LOCK(conn); + } + } + SESS_MTX_UNLOCK(conn); + } + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params", + data, data_len); + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + if(data_len == 0) { + xfree(data); + data = NULL; + } + rsp_pdu.data = data; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_TEXT_RSP; + BDADD8(&rsp[1], F_bit, 7); + BDADD8(&rsp[1], C_bit, 6); + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], data_len); // DataSegmentLength + + DSET64(&rsp[8], lun); + DSET32(&rsp[16], task_tag); + if (F_bit) { + DSET32(&rsp[20], 0xffffffffU); + } else { + transfer_tag = 1 + conn->id; + DSET32(&rsp[20], transfer_tag); + } + + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + if (I_bit == 0) { + conn->sess->ExpCmdSN++; + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + } + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + istgt_iscsi_param_free(params); + return -1; + } + + /* update internal variables */ + istgt_iscsi_copy_param2var(conn); + /* check value */ + rc = istgt_iscsi_check_values(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_check_values() failed\n"); + istgt_iscsi_param_free(params); + return -1; + } + + istgt_iscsi_param_free(params); + return 0; +} + +static int +istgt_iscsi_op_logout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + char buf[MAX_TMPBUF]; + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + uint32_t task_tag; + uint16_t cid; + uint32_t CmdSN; + uint32_t ExpStatSN; + int reason; + int response; + int data_len; + int rc; + + data_len = 0; + cp = (uint8_t *) &pdu->bhs; + reason = BGET8W(&cp[1], 6, 7); + + task_tag = DGET32(&cp[16]); + cid = DGET16(&cp[20]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "reason=%d, ITT=%x, cid=%d\n", + reason, task_tag, cid); + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n", + CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN, + conn->sess->MaxCmdSN); + if (CmdSN != conn->sess->ExpCmdSN) { + ISTGT_WARNLOG("CmdSN(%u) might have dropped\n", CmdSN); + /* ignore error */ + } + SESS_MTX_UNLOCK(conn); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n", + CmdSN, ExpStatSN, conn->StatSN); + } + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + } + if (SN32_GT(ExpStatSN, conn->StatSN)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n", + ExpStatSN); + conn->StatSN = ExpStatSN; + } + if (ExpStatSN != conn->StatSN) { + ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n", + ExpStatSN, conn->StatSN); + /* ignore error */ + } + if (conn->sess != NULL) { + SESS_MTX_UNLOCK(conn); + } + + response = 0; // connection or session closed successfully + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = NULL; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_LOGOUT_RSP; + BDADD8W(&rsp[1], 1, 7, 1); + rsp[2] = response; + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], data_len); // DataSegmentLength + + DSET32(&rsp[16], task_tag); + + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + if (conn->sess->connections == 1) { + conn->sess->ExpCmdSN++; + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + } + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + } else { + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + DSET32(&rsp[28], CmdSN); + DSET32(&rsp[32], CmdSN); + } + + DSET16(&rsp[40], 0); // Time2Wait + DSET16(&rsp[42], 0); // Time2Retain + + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + + SESS_MTX_LOCK(conn); + if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) { + snprintf(buf, sizeof buf, "Logout from %s (%s) on %s LU%d" + " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u," + " CID=%u, HeaderDigest=%s, DataDigest=%s\n", + conn->initiator_name, conn->initiator_addr, + conn->target_name, conn->sess->lu->num, + conn->portal.host, conn->portal.port, conn->portal.tag, + conn->sess->isid, conn->sess->tsih, conn->cid, + (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C") + ? "on" : "off"), + (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C") + ? "on" : "off")); + ioctl_call(conn, TYPE_LOGOUT); + } else { + /* discovery session */ + snprintf(buf, sizeof buf, "Logout(discovery) from %s (%s) on" + " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u," + " CID=%u, HeaderDigest=%s, DataDigest=%s\n", + conn->initiator_name, conn->initiator_addr, + conn->portal.host, conn->portal.port, conn->portal.tag, + conn->sess->isid, conn->sess->tsih, conn->cid, + (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C") + ? "on" : "off"), + (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C") + ? "on" : "off")); + } + SESS_MTX_UNLOCK(conn); + istgt_connection_status(conn, "SUCCESSFULL LOGOUT"); + + ISTGT_NOTICELOG("%s", buf); + + conn->exec_logout = 1; + return 0; +} + +static int istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); + +static int +istgt_iscsi_transfer_in(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + int rc; + + //MTX_LOCK(&conn->wpdu_mutex); + rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd); + //MTX_UNLOCK(&conn->wpdu_mutex); + return rc; +} + +static int +istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *data; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t DataSN; + int transfer_len; + int data_len; + int segment_len; + int offset; + int F_bit, O_bit, U_bit, S_bit; + int residual_len; + int sent_status; + int len; + int rc; + const char *msg = ""; + int segs = 0; + data = lu_cmd->data; + transfer_len = lu_cmd->transfer_len; + data_len = lu_cmd->data_len; + segment_len = conn->MaxRecvDataSegmentLength; + + F_bit = O_bit = U_bit = S_bit = 0; + if (data_len < transfer_len) { + /* underflow */ + msg = "Underflow"; + residual_len = transfer_len - data_len; + transfer_len = data_len; + U_bit = 1; + } else if (data_len > transfer_len) { + /* overflow */ + msg = "Overflow"; + residual_len = data_len - transfer_len; + O_bit = 1; + } else { + residual_len = 0; + } + + task_tag = lu_cmd->task_tag; + transfer_tag = 0xffffffffU; + DataSN = 0; + sent_status = 0; + + /* send data splitted by segment_len */ + for (offset = 0; offset < transfer_len; offset += segment_len) { + len = DMIN32(segment_len, (transfer_len - offset)); + if (offset + len > transfer_len) { + ISTGT_ERRLOG("transfer missing\n"); + return -1; + } else if (offset + len == transfer_len) { + /* final PDU */ + F_bit = 1; + S_bit = 0; + if (lu_cmd->sense_data_len == 0 + && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD + || lu_cmd->status == ISTGT_SCSI_STATUS_CONDITION_MET + || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE + || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE_CONDITION_MET)) { + S_bit = 1; + sent_status = 1; + } + } else { + F_bit = 0; + S_bit = 0; + } + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "sending:%d, from:%u %d bytes of(%u/%u /%u %s) StatSN=%u, DataSN=%u\n", + segs, offset, len, transfer_len, data_len, residual_len, msg, + conn->StatSN, DataSN); + ++segs; + + /* DATA PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = data + offset; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_SCSI_DATAIN; + BDADD8(&rsp[1], F_bit, 7); + BDADD8(&rsp[1], 0, 6); // A_bit Acknowledge + if (F_bit && S_bit) { + BDADD8(&rsp[1], O_bit, 2); + BDADD8(&rsp[1], U_bit, 1); + } else { + BDADD8(&rsp[1], 0, 2); + BDADD8(&rsp[1], 0, 1); + } + BDADD8(&rsp[1], S_bit, 0); + if (S_bit) { + rsp[3] = lu_cmd->status; + } else { + rsp[3] = 0; // Status or Rsvd + } + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], len); // DataSegmentLength + + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], transfer_tag); + + SESS_MTX_LOCK(conn); + if (S_bit) { + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + } else { + DSET32(&rsp[24], 0); // StatSN or Reserved + } + if (F_bit && S_bit && lu_cmd->I_bit == 0 ) { + if(likely(lu_cmd->lu->limit_q_size==0 || ((int)(conn->sess->MaxCmdSN - conn->sess->ExpCmdSN) < lu_cmd->lu->limit_q_size))){ + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + if(unlikely((conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local) && (lu_cmd->lu->limit_q_size == 0))) { + ISTGT_LOG("conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local in transfer internal\n"); + conn->sess->MaxCmdSN = conn->sess->MaxCmdSN_local; + } + } else + conn->sess->MaxCmdSN_local++; + } + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + + DSET32(&rsp[36], DataSN); + DataSN++; + + DSET32(&rsp[40], (uint32_t) offset); + if (F_bit && S_bit) { + DSET32(&rsp[44], residual_len); + } else { + DSET32(&rsp[44], 0); + } + + rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + } + + if (sent_status) { + return 1; + } + return 0; +} + +static void +parse_scsi_cdb(ISTGT_LU_CMD_Ptr lu_cmd) +{ +#define setinf1() { \ + if (dpo) lu_cmd->info[lu_cmd->infdx++] = 'd'; \ + if (fua) lu_cmd->info[lu_cmd->infdx++] = 'f'; \ + if (fua_nv) lu_cmd->info[lu_cmd->infdx++] = 'n'; \ +} + int sync_nv = 0, immed = 0; + int sa = 0; + int NOR = 0, NOW = 0, inv = 0; + int dpo = 0, fua = 0, fua_nv = 0; // cdb[1] bits 4, 3, 1 + int bytchk = 0; //cdb[1] bits 1 + int anchor = 0, unmap = 0; //cdb[1] bits 4, 3 + int pbdata = 0, lbdata = 0; //cdb[1] bits 2, 1 + uint64_t lba = 0; + uint32_t len = 0;; + uint32_t transfer_len = 0; //uint32_t parameter_len; + uint8_t *cdb = lu_cmd->cdb; + + uint8_t sidx = istgt_cmd_table[cdb[0]].statidx; + SCSIstat_rest[sidx].opcode = cdb[0]; + ++SCSIstat_rest[sidx].req_start; + + lu_cmd->infdx = 0; + lu_cmd->cdbflags = 0; + lu_cmd->cdb0 = cdb[0]; + lu_cmd->lba = 0; + lu_cmd->lblen = 0; + + /* + ISTGT_LU_DISK *spec = NULL; + int lun_i = istgt_lu_islun2lun(lu_cmd->lun); + if (lun_i < lu_cmd->lu->maxlun) + spec = (ISTGT_LU_DISK *) (lu_cmd->lu->lun[lun_i].spec); + */ + switch(cdb[0]) { + /*.................... + case SBC_READ_6: + case SBC_WRITE_6: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) (DGET24(&lu_cmd->cdb[1]) & 0x001fffffU); + lu_cmd->lblen = (uint32_t) DGET8(&lu_cmd->cdb[4]); + break; + case SBC_READ_10: + case SBC_WRITE_10: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET32(&lu_cmd->cdb[2]); + lu_cmd->lblen = (uint32_t) DGET16(&lu_cmd->cdb[7]); + break; + case SBC_WRITE_AND_VERIFY_10: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET32(&lu_cmd->cdb[2]) + lu_cmd->lblen = (uint32_t) DGET16(&lu_cmd->cdb[7]); + break; + case SBC_READ_12: + case SBC_WRITE_12: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET32(&lu_cmd->cdb[2]); + lu_cmd->lblen = (uint32_t) DGET32(&lu_cmd->cdb[6]); + break; + case SBC_WRITE_AND_VERIFY_12: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET32(&lu_cmd->cdb[2]); + lu_cmd->lblen = (uint32_t) DGET32(&lu_cmd->cdb[6]); + break; + case SBC_READ_16: + case SBC_WRITE_16: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET64(&lu_cmd->cdb[2]); + lu_cmd->lblen = (uint32_t) DGET32(&lu_cmd->cdb[10]); + break; + case SBC_WRITE_AND_VERIFY_16: + lu_cmd->cdb0 = lu_cmd->cdb[0]; + lu_cmd->lba = (uint64_t) DGET64(&lu_cmd->cdb[2]); + lu_cmd->lblen = (uint32_t) DGET32(&lu_cmd->cdb[10]); + break; + .................*/ + case SBC_READ_6: + if (lu_cmd->R_bit == 0) + NOR=1; + lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU); + transfer_len = (uint32_t) DGET8(&cdb[4]); + if (transfer_len == 0) + transfer_len = 256; + break; + + case SBC_READ_10: + if (lu_cmd->R_bit == 0) + NOR=1; + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + break; + + case SBC_READ_12: + if (lu_cmd->R_bit == 0) + NOR=1; + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[6]); + break; + + case SBC_READ_16: + if (lu_cmd->R_bit == 0) + NOR=1; + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + break; + + case SBC_WRITE_6: + if (lu_cmd->W_bit == 0) + NOW=1; //WBit not set to 1 + lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU); + transfer_len = (uint32_t) DGET8(&cdb[4]); + if (transfer_len == 0) + transfer_len = 256; + break; + + case SBC_WRITE_10: + case SBC_WRITE_AND_VERIFY_10: + if (lu_cmd->W_bit == 0) + NOW=1; //WBit not set to 1 + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + break; + + case SBC_WRITE_12: + case SBC_WRITE_AND_VERIFY_12: + if (lu_cmd->W_bit == 0) + NOW=1; //WBit not set to 1 + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[6]); + break; + + case SBC_WRITE_16: + case SBC_WRITE_AND_VERIFY_16: + if (lu_cmd->W_bit == 0) + NOW=1; //WBit not set to 1 + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + break; + + case SBC_VERIFY_10: + dpo = BGET8(&cdb[1], 4); + bytchk = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET16(&cdb[7]); + break; + + case SBC_VERIFY_12: + dpo = BGET8(&cdb[1], 4); + bytchk = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET32(&cdb[6]); + break; + + case SBC_VERIFY_16: + dpo = BGET8(&cdb[1], 4); + bytchk = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET64(&cdb[2]); + len = (uint32_t) DGET32(&cdb[10]); + break; + + case SBC_WRITE_SAME_10: + if (lu_cmd->W_bit == 0) + NOW=1; + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + if (pbdata) + lu_cmd->info[lu_cmd->infdx++] = 'P'; + if (lbdata) + lu_cmd->info[lu_cmd->infdx++] = 'L'; + /* only PBDATA=0 and LBDATA=0 support */ + if (pbdata || lbdata) + inv = 1; //(ILLEGAL_REQUEST, 0x24, 0x00); + break; + + case SBC_WRITE_SAME_16: + if (lu_cmd->W_bit == 0) + NOW=1; + anchor = BGET8(&cdb[1], 4); + unmap = BGET8(&cdb[1], 3); + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + if (unmap) + lu_cmd->info[lu_cmd->infdx++] = 'U'; + if (pbdata) + lu_cmd->info[lu_cmd->infdx++] = 'P'; + if (lbdata) + lu_cmd->info[lu_cmd->infdx++] = 'L'; + /* only PBDATA=0 and LBDATA=0 support */ + if (pbdata || lbdata) + inv = 1; //(ILLEGAL_REQUEST, 0x24, 0x00); + if (anchor) + inv = 1; //(ILLEGAL_REQUEST, 0x24, 0x00); + break; + + case SBC_COMPARE_AND_WRITE: + if (lu_cmd->W_bit == 0) + NOW=1; + dpo = BGET8(&cdb[1], 4); + fua = BGET8(&cdb[1], 3); + fua_nv = BGET8(&cdb[1], 1); + setinf1() + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET8(&cdb[13]); + + /*maxlen = ISTGT_LU_WORK_ATS_BLOCK_SIZE / spec->blocklen; + if (maxlen > 0xff) + maxlen = 0xff; + if (transfer_len > maxlen) + inv = 1;*/ + break; + + case SBC_SYNCHRONIZE_CACHE_10: + sync_nv = BGET8(&cdb[1], 2); + immed = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET16(&cdb[7]); + //if (len == 0) + // len = spec->blockcnt; + break; + + case SBC_SYNCHRONIZE_CACHE_16: + sync_nv = BGET8(&cdb[1], 2); + immed = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET64(&cdb[2]); + len = (uint32_t) DGET32(&cdb[10]); + //if (len == 0) + // len = spec->blockcnt; + break; + + case SBC_READ_DEFECT_DATA_10: + //case SBC_READ_DEFECT_DATA_16: + if (lu_cmd->R_bit == 0) + NOR=1; + break; + + case SCC_MAINTENANCE_IN: + sa = BGET8W(&cdb[1], 4, 5); + if (sa == SPC_MI_REPORT_TARGET_PORT_GROUPS) { + if (lu_cmd->R_bit == 0) + NOR=1; + //alen = DGET32(&cdb[6]); + } + break; + + case SCC_MAINTENANCE_OUT: + sa = BGET8W(&cdb[1], 4, 5); + if (sa == SPC_MO_SET_TARGET_PORT_GROUPS) { + if (lu_cmd->W_bit == 0) + NOW=1; + //parameter_len = DGET32(&cdb[6]); + } + break; + + case SPC_PERSISTENT_RESERVE_IN: + sa = BGET8W(&cdb[1], 4, 5); + if (lu_cmd->R_bit == 0) + NOR=1; + //alen = DGET16(&cdb[7]); + break; + + case SPC_PERSISTENT_RESERVE_OUT: + if (lu_cmd->W_bit == 0) + NOW=1; + sa = BGET8W(&cdb[1], 4, 5); + //parameter_len = DGET32(&cdb[5]); + break; + + case SPC_EXTENDED_COPY: + sa = BGET8W(&cdb[1], 4, 5); /* LID1 - 00h / LID4 - 01h */ + if (sa != 0x00) + inv = 1;/* INVALID COMMAND SERVICE ACTION */ + break; + case SPC2_RELEASE_6: + break; + case SPC2_RELEASE_10: + break; + case SPC2_RESERVE_6: + break; + case SPC2_RESERVE_10: + break; + case SBC_UNMAP: + break; + default: + break; + } + //if (NOR == 0 && NOW == 0) { + //} + lu_cmd->lba = lba; + if (transfer_len != 0) + lu_cmd->lblen = transfer_len; + else + lu_cmd->lblen = len; + + lu_cmd->dpo = dpo == 1 ? 1 : 0; + lu_cmd->fua = fua == 1 ? 1 : 0; + lu_cmd->fua_nv = fua_nv == 1 ? 1 : 0; + lu_cmd->bytchk = bytchk == 1 ? 1 : 0; + lu_cmd->anchor = anchor == 1 ? 1 : 0; + lu_cmd->unmap = unmap == 1 ? 1 : 0; + lu_cmd->pbdata = pbdata == 1 ? 1 : 0; + lu_cmd->lbdata = lbdata == 1 ? 1 : 0; + lu_cmd->sync_nv = sync_nv == 1 ? 1 : 0; + lu_cmd->immed = immed == 1 ? 1 : 0; + if (NOW) { + lu_cmd->info[lu_cmd->infdx++] = '-'; + lu_cmd->info[lu_cmd->infdx++] = 'W'; + } else if (NOR) { + lu_cmd->info[lu_cmd->infdx++] = '-'; + lu_cmd->info[lu_cmd->infdx++] = 'R'; + } + lu_cmd->info[lu_cmd->infdx] = '\0'; +} + +void +timediff(ISTGT_LU_CMD_Ptr p, char ch, uint16_t line) +{ + p->_lst = p->_andx; + int _inx = ++(p->_andx); + struct timespec *_s = &(p->times[_inx-1]); + struct timespec *_n = &(p->times[_inx]); + struct timespec *_r = &(p->tdiff[_inx]); + clock_gettime(clockid, _n); + p->caller[_inx] = ch ? ch : '_'; + p->line[_inx] = line; + if (p->_andx >= _PSZ-1) { + p->times[0] = p->times[_inx]; + p->_andx = 0; + ++p->_roll_cnt; + } else { + p->caller[_inx+1] = '\0'; + } + if ((_n->tv_nsec - _s->tv_nsec) < 0) { + _r->tv_sec = _n->tv_sec - _s->tv_sec-1; + _r->tv_nsec = 1000000000 + _n->tv_nsec - _s->tv_nsec; + } else { + _r->tv_sec = _n->tv_sec - _s->tv_sec; + _r->tv_nsec = _n->tv_nsec - _s->tv_nsec; + } +} + +static int +istgt_iscsi_op_scsi(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + int istgt_state, lunum; + ISTGT_LU_Ptr lu; + ISTGT_LU_CMD lu_cmd; + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + //uint8_t *data; + uint8_t *cdb; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_len; + uint32_t CmdSN; + uint32_t ExpStatSN; + size_t bidi_residual_len; + size_t residual_len; + size_t data_len; + int I_bit, F_bit, R_bit, W_bit, Attr_bit; + int o_bit, u_bit, O_bit, U_bit; + int rc; + uint32_t c_StatSN , s_ExpCmdSN, s_MaxCmdSN; + uint32_t QCmdSN; + int s_conns; + int operation_mode = 0; + const char *msg = "", *que= ""; + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + + data_len = 0; + + cp = (uint8_t *) &pdu->bhs; + I_bit = BGET8(&cp[0], 6); + F_bit = BGET8(&cp[1], 7); + R_bit = BGET8(&cp[1], 6); + W_bit = BGET8(&cp[1], 5); + Attr_bit = BGET8W(&cp[1], 2, 3); + + lun = DGET64(&cp[8]); + task_tag = DGET32(&cp[16]); + transfer_len = DGET32(&cp[20]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + + cdb = &cp[32]; + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, 16); +#if 0 + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN); +#endif + + SESS_MTX_LOCK(conn); + c_StatSN = conn->StatSN; + s_ExpCmdSN = conn->sess->ExpCmdSN; + s_MaxCmdSN = conn->sess->MaxCmdSN; + s_conns = conn->sess->connections; + if (conn->sess->lu && conn->sess->lu->istgt) + operation_mode = conn->sess->lu->istgt->OperationalMode; + lu = conn->sess->lu; + lunum = lu ? lu->num : -1; + SESS_MTX_UNLOCK(conn); + + lu_cmd.cdb = cdb; + parse_scsi_cdb(&lu_cmd); + lu_cmd.task_tag = task_tag; + lu_cmd.transfer_len = transfer_len; + + lu_cmd.I_bit = I_bit; + lu_cmd.F_bit = F_bit; + lu_cmd.R_bit = R_bit; + lu_cmd.W_bit = W_bit; + lu_cmd.Attr_bit = Attr_bit; + lu_cmd.lun = lun; + lu_cmd.CmdSN = CmdSN; + lu_cmd.flags = 0; + + lu_cmd.times[0] = pdu->start; + lu_cmd.caller[0] = 'i'; + lu_cmd._andx = 0; + lu_cmd._lst = 0; + lu_cmd._roll_cnt = 0; + timediff(&lu_cmd, 'b', __LINE__); + lu_cmd.lunum = lunum; + + lu_cmd.iobufindx = -1; + lu_cmd.iobufsize = 0; + lu_cmd.data = NULL; //data; + lu_cmd.data_len = 0; + lu_cmd.alloc_len = 0; //alloc_len; + lu_cmd.status = 0; + lu_cmd.sense_data = NULL; //xmalloc(conn->snsbufsize); + lu_cmd.sense_alloc_len = 0; //conn->snsbufsize; + lu_cmd.sense_data_len = 0; + lu_cmd.connGone = 0; + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "LU%d: CSN:%x ITT:%x (%lu/%u)[0x%x %lx+%x] PG=0x%4.4x, LUN=0x%lx " + "ExpStatSN=%x StatSN=%x ExpCmdSN=%x MaxCmdSN=%x " + "%c%c%c%c Attr%d\n", + lunum, CmdSN, + task_tag, pdu->data_segment_len, transfer_len, + lu_cmd.cdb0, lu_cmd.lba, lu_cmd.lblen, + conn->portal.tag, lun, // lu->name, + ExpStatSN, c_StatSN, s_ExpCmdSN, s_MaxCmdSN, + I_bit ? 'I' : ' ', F_bit ? 'F' : ' ', R_bit ? 'R' : ' ', W_bit ? 'W' : ' ', + Attr_bit); + + if (I_bit == 0) { + /* XXX MCS reverse order? */ + if (SN32_GT(CmdSN, s_ExpCmdSN)) { + if (s_conns > 1) { + struct timespec abstime; + time_t start, now; + + start = now = time(NULL); + memset(&abstime, 0, sizeof abstime); + abstime.tv_sec = now + (MAX_MCSREVWAIT / 1000); + abstime.tv_nsec = (MAX_MCSREVWAIT % 1000) * 1000000; + + rc = 0; + SESS_MTX_LOCK(conn); + while (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) { + conn->sess->req_mcs_cond++; + rc = pthread_cond_timedwait(&conn->sess->mcs_cond, + &conn->sess->mutex, + &abstime); + if (rc == ETIMEDOUT) { + if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) { + rc = -1; + /* timeout */ + break; + } + /* OK cond */ + rc = 0; + break; + } + if (rc != 0) { + break; + } + } + c_StatSN = conn->StatSN; + s_ExpCmdSN = conn->sess->ExpCmdSN; + s_MaxCmdSN = conn->sess->MaxCmdSN; + s_conns = conn->sess->connections; + if (conn->sess->lu && conn->sess->lu->istgt) + operation_mode = conn->sess->lu->istgt->OperationalMode; + if (I_bit == 0) { + if (SN32_GT(CmdSN, s_ExpCmdSN)) + conn->sess->ExpCmdSN = CmdSN; + } else if (CmdSN == s_ExpCmdSN) { + if (SN32_GT(ExpStatSN, c_StatSN)) + conn->StatSN = ExpStatSN; + } + SESS_MTX_UNLOCK(conn); + if (rc < 0) { + now = time(NULL); + ISTGT_ERRLOG("MCS: CmdSN(%u) error ExpCmdSN=%u " + "(time=%f)\n", + CmdSN, s_ExpCmdSN, + difftime(now, start)); + return -1; + } +#if 0 + ISTGT_WARNLOG("MCS: reverse CmdSN=%u(retry=%d, yields=%d)\n", + CmdSN, retry, try_yields); +#endif + } + } + } + + if (I_bit == 0) { + if (SN32_LT(CmdSN, s_ExpCmdSN) + || SN32_GT(CmdSN, s_MaxCmdSN)) { + ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n", + CmdSN, s_ExpCmdSN, s_MaxCmdSN); + return -1; + } + if (SN32_GT(CmdSN, s_ExpCmdSN)) { + ISTGT_WARNLOG("CmdSN(%u) > ExpCmdSN(%u)\n", + CmdSN, s_ExpCmdSN); + } + } else if (CmdSN != s_ExpCmdSN) { + ISTGT_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n", + CmdSN, s_ExpCmdSN); + return -1; + } + if (SN32_GT(ExpStatSN, c_StatSN)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n", + ExpStatSN); + } + + + SESS_MTX_LOCK(conn); + if (conn->sess->lu && conn->sess->lu->istgt) + operation_mode = conn->sess->lu->istgt->OperationalMode; + if (I_bit == 0) { + if (SN32_GT(CmdSN, s_ExpCmdSN)) + s_ExpCmdSN = conn->sess->ExpCmdSN = CmdSN; + } else if (CmdSN == s_ExpCmdSN) { + if (SN32_GT(ExpStatSN, c_StatSN)) + c_StatSN = conn->StatSN = ExpStatSN; + } + + QCmdSN = s_MaxCmdSN - s_ExpCmdSN + 1 + conn->queue_depth; + if (SN32_LT(ExpStatSN + QCmdSN, c_StatSN)) { + SESS_MTX_UNLOCK(conn); + ISTGT_ERRLOG("StatSN(%u/%u) QCmdSN(%u) error\n", + ExpStatSN, c_StatSN, QCmdSN); + return -1; + } + + lu_cmd.pdu = pdu; + lu_cmd.lu = conn->sess->lu; + if (I_bit == 0) { + conn->sess->ExpCmdSN++; + if (conn->sess->req_mcs_cond > 0) { + conn->sess->req_mcs_cond--; + rc = pthread_cond_broadcast(&conn->sess->mcs_cond); + if (rc != 0) { + SESS_MTX_UNLOCK(conn); + ISTGT_ERRLOG("cond_broadcast() failed\n"); + return -1; + } + } + } + SESS_MTX_UNLOCK(conn); + + if (R_bit != 0 && W_bit != 0) { + ISTGT_ERRLOG("Bidirectional CDB is not supported\n"); + return -1; + } + if (lu == NULL) { + ISTGT_ERRLOG("lu not found\n"); + return -1; + } + + istgt_state = istgt_get_state(lu->istgt); + if (istgt_state == ISTGT_STATE_EXITING || istgt_state == ISTGT_STATE_SHUTDOWN) { + ISTGT_ERRLOG("istgt shutting down\n"); + rc = 0; + } else if (lu->online == 0) { + ISTGT_ERRLOG("LU%d: offline\n", lu->num); + /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */ + istgt_lu_scsi_build_sense_data(&lu_cmd, + ISTGT_SCSI_SENSE_NOT_READY, + 0x04, 0x00); + lu_cmd.status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + rc = 0; + } else if (lu->type != ISTGT_LU_TYPE_DISK) { + ISTGT_ERRLOG("LU%d: type:%d is not disk\n", lu->num, lu->type); + /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */ + istgt_lu_scsi_build_sense_data(&lu_cmd, + ISTGT_SCSI_SENSE_NOT_READY, + 0x04, 0x00); + lu_cmd.status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + rc = 0; + } else { + + /* need R2T? */ + if (!operation_mode && (W_bit && F_bit) && (conn->max_r2t > 0)) { + if (lu_cmd.pdu->data_segment_len < transfer_len) { + rc = istgt_add_transfer_task(conn, &lu_cmd); + if (rc < 0) { + ISTGT_ERRLOG("add_transfer_task() failed\n"); + return -1; + } + } + } + + /* execute SCSI command */ + rc = istgt_lu_disk_queue(conn, &lu_cmd); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue() failed\n", lu->num); + return -1; + } + switch (rc) { + case ISTGT_LU_TASK_RESULT_QUEUE_OK: + return 0; + case ISTGT_LU_TASK_RESULT_QUEUE_FULL: + que = "QueueFull "; + ISTGT_WARNLOG("Queue Full\n"); + break; + case ISTGT_LU_TASK_RESULT_IMMEDIATE: + que = "Immediate "; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Immediate\n"); + break; + default: + ISTGT_ERRLOG("lu_disk_queue unknown rc=%d\n", rc); + return -1; + } + } + + /* transfer data from logical unit */ + /* (direction is view of initiator side) */ + if (lu_cmd.R_bit + && (lu_cmd.status == ISTGT_SCSI_STATUS_GOOD + || lu_cmd.sense_data_len != 0)) { + rc = istgt_iscsi_transfer_in(conn, &lu_cmd); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_transfer_in() failed\n"); + return -1; + } + if (rc > 0) { + /* sent status by last DATAIN PDU */ + return 0; + } + } + + o_bit = u_bit = O_bit = U_bit = 0; + bidi_residual_len = residual_len = 0; + data_len = lu_cmd.data_len; + if (transfer_len != 0 + && lu_cmd.status == ISTGT_SCSI_STATUS_GOOD) { + if (data_len < transfer_len) { + /* underflow */ + msg = "Underflow"; + residual_len = transfer_len - data_len; + U_bit = 1; + } else if (data_len > transfer_len) { + /* overflow */ + msg = "Overflow"; + residual_len = data_len - transfer_len; + O_bit = 1; + } else { + msg = "Transfer"; + } + } + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_SCSI_RSP; + BDADD8(&rsp[1], 1, 7); + BDADD8(&rsp[1], o_bit, 4); + BDADD8(&rsp[1], u_bit, 3); + BDADD8(&rsp[1], O_bit, 2); + BDADD8(&rsp[1], U_bit, 1); + rsp[2] = 0x00; // Command Completed at Target + //rsp[2] = 0x01; // Target Failure + rsp[3] = lu_cmd.status; + rsp[4] = 0; // TotalAHSLength + rsp_pdu.data = lu_cmd.sense_data; + DSET24(&rsp[5], lu_cmd.sense_data_len); // DataSegmentLength + rsp_pdu.data_segment_len = lu_cmd.sense_data_len; + lu_cmd.sense_data = NULL; lu_cmd.sense_data_len = 0; + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], 0); // SNACK Tag + + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + if(I_bit == 0) { + if(likely((lu_cmd.lu->limit_q_size==0) || ((int)(conn->sess->MaxCmdSN - conn->sess->ExpCmdSN) < lu_cmd.lu->limit_q_size))){ + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + if(unlikely((conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local) && (lu_cmd.lu->limit_q_size == 0))) { + ISTGT_LOG("conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local in op_scsi\n"); + conn->sess->MaxCmdSN = conn->sess->MaxCmdSN_local; + } + } else + conn->sess->MaxCmdSN_local++; + } + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + + DSET32(&rsp[36], 0); // ExpDataSN + DSET32(&rsp[40], bidi_residual_len); + DSET32(&rsp[44], residual_len); + + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + if (lu_cmd.sense_data != NULL) + xfree(lu_cmd.sense_data); + if (lu_cmd.data != NULL) + xfree(lu_cmd.data); + return -1; + } + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "op_scsi_done: status:%d %s, CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u" + "I=%d, F=%d, R=%d, W=%d, Attr=%d, ITT=%x, TL=%u (%s %lu)\n", + lu_cmd.status, que, CmdSN, ExpStatSN, c_StatSN, s_ExpCmdSN, s_MaxCmdSN, + I_bit, F_bit, R_bit, W_bit, Attr_bit, + task_tag, transfer_len, msg, data_len); + if (lu_cmd.sense_data != NULL) + xfree(lu_cmd.sense_data); + if (lu_cmd.data != NULL) + xfree(lu_cmd.data); + return 0; +} + +static int +istgt_iscsi_task_response(CONN_Ptr conn, ISTGT_LU_TASK_Ptr lu_task) +{ + ISTGT_LU_CMD_Ptr lu_cmd; + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint32_t task_tag; + uint32_t transfer_len; + uint32_t CmdSN; + size_t residual_len; + size_t data_len; + int I_bit; + int o_bit, u_bit, O_bit, U_bit; + int bidi_residual_len; + int rc; + uint64_t *tptr; + const char *msg = NULL; + lu_cmd = &lu_task->lu_cmd; + ISTGT_SCSI_STATUS lstat = lu_cmd->status; + transfer_len = lu_cmd->transfer_len; + task_tag = lu_cmd->task_tag; + I_bit = lu_cmd->I_bit; + CmdSN = lu_cmd->CmdSN; + + uint8_t sidx = istgt_cmd_table[lu_cmd->cdb0].statidx; + + ++SCSIstat_rest[sidx].req_finish; + + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "SCSI response CSN=%x/%x tt:%x tl:%x\n", CmdSN, lu_cmd->status, task_tag, transfer_len); + + /* transfer data from logical unit */ + /* (direction is view of initiator side) */ + if (lu_cmd->R_bit + && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD + || lu_cmd->sense_data_len != 0)) { + if (lu_task->lock) { + rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd); + } else { + rc = istgt_iscsi_transfer_in(conn, lu_cmd); + } + if (rc < 0) { + ISTGT_ERRLOG("iscsi_transfer_in() failed\n"); + return -1; + } + if (rc > 0) { + /* sent status by last DATAIN PDU */ + return 0; + } + } + + o_bit = u_bit = O_bit = U_bit = 0; + bidi_residual_len = residual_len = 0; + data_len = lu_cmd->data_len; + if (transfer_len != 0 + && lu_cmd->status == ISTGT_SCSI_STATUS_GOOD) { + if (data_len < transfer_len) { + /* underflow */ + msg = "underflow"; + residual_len = transfer_len - data_len; + U_bit = 1; + } else if (data_len > transfer_len) { + /* overflow */ + msg = "overflow"; + residual_len = data_len - transfer_len; + O_bit = 1; + } else { + msg = "transfer"; + } + } + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = lu_cmd->sense_data; + tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + rsp[0] = ISCSI_OP_SCSI_RSP; + BDADD8(&rsp[1], 1, 7); + BDADD8(&rsp[1], o_bit, 4); + BDADD8(&rsp[1], u_bit, 3); + BDADD8(&rsp[1], O_bit, 2); + BDADD8(&rsp[1], U_bit, 1); + rsp[2] = 0x00; // Command Completed at Target + //rsp[2] = 0x01; // Target Failure + rsp[3] = lu_cmd->status; + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], lu_cmd->sense_data_len); // DataSegmentLength + rsp_pdu.data_segment_len = lu_cmd->sense_data_len; + + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], 0); // SNACK Tag + + SESS_MTX_LOCK(conn); + DSET32(&rsp[24], conn->StatSN); + conn->StatSN++; + if (I_bit == 0) { + if(likely(lu_cmd->lu->limit_q_size==0 || ((int)(conn->sess->MaxCmdSN - conn->sess->ExpCmdSN) < lu_cmd->lu->limit_q_size))) { + conn->sess->MaxCmdSN++; + conn->sess->MaxCmdSN_local++; + if(unlikely((conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local) && (lu_cmd->lu->limit_q_size == 0))) { + ISTGT_LOG("conn->sess->MaxCmdSN != conn->sess->MaxCmdSN_local\n"); + conn->sess->MaxCmdSN = conn->sess->MaxCmdSN_local; + } + } + else + conn->sess->MaxCmdSN_local++; + } + + DSET32(&rsp[28], conn->sess->ExpCmdSN); + DSET32(&rsp[32], conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + + DSET32(&rsp[36], 0); // ExpDataSN + DSET32(&rsp[40], bidi_residual_len); + DSET32(&rsp[44], residual_len); + + if (lu_task->lock) { + rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu); + } else { + rc = istgt_iscsi_write_pdu(conn, &rsp_pdu); + } + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + if (msg) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SCSI response CSN=%x done, status:%x %s %zu/%u\n", + CmdSN, lstat, msg, data_len, transfer_len); + } + return 0; +} + +static int +istgt_iscsi_op_task(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + uint64_t lun; + uint32_t task_tag; + uint32_t ref_task_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + uint32_t ref_CmdSN; + int I_bit; + int function; + int response; + int rc; + int cleared = 0; + uint32_t cStatSN, nStatSN = 0, sExpCmdSN, nExpCmdSN = 0, sMaxCmdSN; + const char *msg = ""; + const char *fname = ""; + char initport[MAX_INITIATOR_NAME]; + ISTGT_LU_DISK *spec; + int cmdqcount = 0; + int blockedqcount = 0; + + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + initport[0] = '\0'; + initport[MAX_INITIATOR_NAME-2] = '\0'; + initport[MAX_INITIATOR_NAME-1] = '\0'; + + cp = (uint8_t *) &pdu->bhs; + I_bit = BGET8(&cp[0], 6); + function = BGET8W(&cp[1], 6, 7); + + lun = DGET64(&cp[8]); + if(lun != 0) + lun = 0; + task_tag = DGET32(&cp[16]); + ref_task_tag = DGET32(&cp[20]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + ref_CmdSN = DGET32(&cp[32]); + + SESS_MTX_LOCK(conn); + cStatSN = conn->StatSN; + nStatSN = cStatSN; + sExpCmdSN = conn->sess->ExpCmdSN; + sMaxCmdSN = conn->sess->MaxCmdSN; + if (CmdSN != conn->sess->ExpCmdSN) { + msg = "dropped?"; + conn->sess->ExpCmdSN = CmdSN; + nExpCmdSN = CmdSN; + } + if (SN32_GT(ExpStatSN, conn->StatSN)) { + msg = "StatSN-advanced!"; + conn->StatSN = ExpStatSN; + nStatSN = ExpStatSN; + } +#if 0 + /* not need */ + if (ExpStatSN != conn->StatSN) { + ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n", + ExpStatSN, conn->StatSN); + conn->StatSN = ExpStatSN; + } +#endif + SESS_MTX_UNLOCK(conn); + spec = (ISTGT_LU_DISK *)(conn->sess->lu->lun[0].spec); + cmdqcount = istgt_queue_count(&spec->cmd_queue); + blockedqcount = istgt_queue_count(&spec->blocked_queue); + + ISTGT_LOG("scsitask:%d start. CmdSN=0x%x, ExpStatSN=0x%x, StatSN=0x%x/0x%x, ExpCmdSN=0x%x/0x%x, MaxCmdSN=0x%x refCmdSN=0x%x (%s) " + "I=%d, ITT=0x%x, ref TT=0x%x cmdqcount=%d, blockedqcount=%d inflight=%d dskIOPending: %d delayedFree: %d, LUN=0x%16.16lx\n", + function, CmdSN, ExpStatSN, cStatSN, nStatSN, sExpCmdSN, nExpCmdSN, + sMaxCmdSN, ref_CmdSN, msg, + I_bit, task_tag, ref_task_tag, cmdqcount, blockedqcount, spec->inflight, conn->diskIoPending, conn->flagDelayedFree, lun); + + response = 0; // Function complete. + switch (function) { + case ISCSI_TASK_FUNC_ABORT_TASK: + fname = "ABORT_TASK"; + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_clear_task_ITLQ(conn, conn->sess->lu, lun, + ref_CmdSN); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + if(cleared == 0 && send_abrt_resp == 1) + response = 1; + istgt_clear_transfer_task(conn, ref_CmdSN); + break; + case ISCSI_TASK_FUNC_ABORT_TASK_SET: + fname = "ABORT_TASK_SET"; + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + if(cleared == 0 && send_abrt_resp == 1) + response = 1; + istgt_clear_all_transfer_task(conn); + break; + case ISCSI_TASK_FUNC_CLEAR_ACA: + fname = "CLEAR_ACA"; + break; + case ISCSI_TASK_FUNC_CLEAR_TASK_SET: + fname = "CLEAR_TASK_SET"; + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + if(cleared == 0 && send_abrt_resp == 1) + response = 1; + istgt_clear_all_transfer_task(conn); + break; + case ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET: + memcpy(initport, conn->initiator_port, MAX_INITIATOR_NAME - 1); + fname = "LOGICAL_UNIT_RESET"; + /* Ravi: Should not be dropping connections on LU_RESET */ + /*istgt_iscsi_drop_all_conns(conn);*/ + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_reset(conn->sess->lu, lun, ISTGT_UA_LUN_RESET); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + //conn->state = CONN_STATE_EXITING; + break; + case ISCSI_TASK_FUNC_TARGET_WARM_RESET: + memcpy(initport, conn->initiator_port, MAX_INITIATOR_NAME - 1); + fname = "TARGET_WARM_RESET"; + /* Ravi: Should not be dropping connections on TGT_RESET */ + /*istgt_iscsi_drop_all_conns(conn); */ + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_reset(conn->sess->lu, lun, ISTGT_UA_TARG_RESET); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + //conn->state = CONN_STATE_EXITING; + break; + case ISCSI_TASK_FUNC_TARGET_COLD_RESET: + memcpy(initport, conn->initiator_port, MAX_INITIATOR_NAME - 1); + fname = "TARGET_COLD_RESET"; + /* This is a obsolete */ + /* Ravi: Should not be dropping connections on TGT_RESET */ + /*istgt_iscsi_drop_all_conns(conn); */ + if(conn->sess->lu != NULL) + MTX_LOCK(&conn->sess->lu->mutex); + SESS_MTX_LOCK(conn); + cleared = istgt_lu_reset(conn->sess->lu, lun, ISTGT_UA_TARG_RESET); + if (cleared <= 0) { + ISTGT_ERRLOG("%s failed rc:%d\n", fname, cleared); + } else { + conn->sess->MaxCmdSN += cleared; + conn->sess->MaxCmdSN_local += cleared; + if(cleared >= 1) + ISTGT_ERRLOG("%s cleared %d commands\n", fname, cleared); + } + SESS_MTX_UNLOCK(conn); + if(conn->sess->lu != NULL) + MTX_UNLOCK(&conn->sess->lu->mutex); + //conn->state = CONN_STATE_EXITING; + break; + case ISCSI_TASK_FUNC_TASK_REASSIGN: + fname = "TASK_REASSIGN"; + break; + default: + fname = "unsupported function"; + response = 255; // Function rejected. + break; + } + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = NULL; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_TASK_RSP; + BDADD8(&rsp[1], 1, 7); + rsp[2] = response; + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], 0); // DataSegmentLength + + DSET32(&rsp[16], task_tag); + + rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, I_bit); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed in iscsi_op_task\n"); + return -1; + } + ISTGT_LOG("scsitask:%d:%s %s done. CSN=0x%x, ExpStatSN=0x%x, StatSN=0x%x/0x%x, ExpCmdSN=0x%x/0x%x, MaxCmdSN=0x%x (%s) " + "I=%d, ITT=0x%x, ref TT=0x%x, LUN=0x%16.16lx\n", + function, fname, initport, CmdSN, ExpStatSN, cStatSN, nStatSN, sExpCmdSN, nExpCmdSN, + conn->sess->MaxCmdSN, msg, + I_bit, task_tag, ref_task_tag, lun); + return 0; +} + +static int +istgt_iscsi_op_nopout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint8_t *cp; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + int I_bit; + int ping_len; + int data_len; + int rc = 0; + uint32_t QCmdSN; + uint32_t s_ExpCmdSN, s_MaxCmdSN, lc_StatSN = 0; + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + + data_len = 0; + + cp = (uint8_t *) &pdu->bhs; + I_bit = BGET8(&cp[0], 6); + ping_len = DGET24(&cp[5]); + + lun = DGET64(&cp[8]); + task_tag = DGET32(&cp[16]); + transfer_tag = DGET32(&cp[20]); + CmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + + SESS_MTX_LOCK(conn); + s_ExpCmdSN = conn->sess->ExpCmdSN; + s_MaxCmdSN = conn->sess->MaxCmdSN; + lc_StatSN = conn->StatSN; + SESS_MTX_UNLOCK(conn); + + if (I_bit == 0) { + if (SN32_LT(CmdSN, s_ExpCmdSN) + || SN32_GT(CmdSN, s_MaxCmdSN)) { + ISTGT_ERRLOG("Ignore CmdSN not in exp range " + "CSN=%x, ExpStatSN=%x, StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x" + "I=%d, ITT=%x, TTT=%x\n", + CmdSN, ExpStatSN, conn->StatSN, s_ExpCmdSN, + s_MaxCmdSN, I_bit, task_tag, transfer_tag); + return -1; + } + } else if (CmdSN != s_ExpCmdSN) { + ISTGT_ERRLOG("CmdSN != ExpCmdSN " + "CSN=%x, ExpStatSN=%x, StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x" + "I=%d, ITT=%x, TTT=%x\n", + CmdSN, ExpStatSN, conn->StatSN, s_ExpCmdSN, + s_MaxCmdSN, I_bit, task_tag, transfer_tag); + return -1; + } + if (SN32_GT(ExpStatSN, conn->StatSN)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%x->%x) advanced " + "CSN=%x, ExpStatSN=%x, StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x" + "I=%d, ITT=%x, TTT=%x\n", + lc_StatSN, ExpStatSN, + CmdSN, ExpStatSN, conn->StatSN, s_ExpCmdSN, + s_MaxCmdSN, I_bit, task_tag, transfer_tag); + lc_StatSN = ExpStatSN; //conn->StatSN = ExpStatSN; + //use_lc = 1; + } + QCmdSN = s_MaxCmdSN - s_ExpCmdSN + 1 + conn->queue_depth; + if (SN32_LT(ExpStatSN + QCmdSN, lc_StatSN)) { + ISTGT_ERRLOG("StatSN(%x/%x) QCmdSN(%x) error " + "CSN=%x, ExpStatSN=%x, StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x" + "I=%d, ITT=%x, TTT=%x\n", + ExpStatSN, lc_StatSN, QCmdSN, + CmdSN, ExpStatSN, conn->StatSN, s_ExpCmdSN, + s_MaxCmdSN, I_bit, task_tag, transfer_tag); + return -1; + } + + if (task_tag == 0xffffffffU) { + if (I_bit == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "got NOPOUT ITT=0xffffffff\n"); + return 0; + } else { + ISTGT_ERRLOG("got NOPOUT ITT=0xffffffff, I=0\n"); + return -1; + } + } + + transfer_tag = 0xffffffffU; + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + if (ping_len != 0) { + /* response of NOPOUT */ + rsp_pdu.data = pdu->data; + data_len = DMIN32(ping_len, conn->MaxRecvDataSegmentLength); + if ((size_t)data_len != pdu->data_segment_len) { + ISTGT_ERRLOG("got NOPOUT d_len:%d != rcvd_len:%lu\n", data_len, pdu->data_segment_len); + } + pdu->data = NULL; + } else { + rsp_pdu.data = NULL; + data_len = 0; + } + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_NOPIN; + BDADD8(&rsp[1], 1, 7); + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], data_len); // DataSegmentLength + + DSET64(&rsp[8], lun); + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], transfer_tag); + + rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, I_bit); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + + return 0; +} + + +static void +istgt_free_transfer_task(ISTGT_R2T_TASK_Ptr r2t_task) +{ + int ind = 0; + if (r2t_task == NULL) + return; + if (r2t_task->iobufindx != -1) { + while ((ind = r2t_task->iobufindx--) > -1) { + xfree(r2t_task->iobuf[ind].iov_base); + } + } + r2t_task->iobufsize = 0; + xfree(r2t_task); +} + +static ISTGT_R2T_TASK_Ptr +istgt_get_transfer_task(CONN_Ptr conn, uint32_t transfer_tag) +{ + ISTGT_R2T_TASK_Ptr r2t_task; + int i; + + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t == 0) { + MTX_UNLOCK(&conn->r2t_mutex); + return NULL; + } + for (i = 0; i < conn->pending_r2t; i++) { + r2t_task = conn->r2t_tasks[i]; +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "CmdSN=%d, TransferTag=%x/%x\n", + r2t_task->CmdSN, r2t_task->transfer_tag, transfer_tag); +#endif + if (r2t_task->transfer_tag == transfer_tag) { + MTX_UNLOCK(&conn->r2t_mutex); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Match index=%d, CmdSN=%d, TransferTag=%x\n", + i, r2t_task->CmdSN, r2t_task->transfer_tag); + return r2t_task; + } + } + MTX_UNLOCK(&conn->r2t_mutex); + return NULL; +} + +static int +istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_R2T_TASK_Ptr r2t_task; + uint32_t transfer_len; + uint32_t transfer_tag; + size_t first_burst_len; + size_t max_burst_len; + size_t data_len; + size_t offset = 0; + int len; + int idx; + int rc; + + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t >= conn->max_r2t) { + // no slot available, skip now... + //ISTGT_WARNLOG("No R2T space available (%d/%d)\n", + // conn->pending_r2t, conn->max_r2t); + MTX_UNLOCK(&conn->r2t_mutex); + return 0; + } + MTX_UNLOCK(&conn->r2t_mutex); + + transfer_len = lu_cmd->transfer_len; + transfer_tag = lu_cmd->task_tag; + data_len = lu_cmd->pdu->data_segment_len; + first_burst_len = conn->FirstBurstLength; + max_burst_len = conn->MaxBurstLength; + offset += data_len; + if (offset >= first_burst_len) { + len = DMIN32(max_burst_len, (transfer_len - offset)); + + r2t_task = xmalloc(sizeof *r2t_task); + r2t_task->conn = conn; + r2t_task->lu = lu_cmd->lu; + r2t_task->lun = lu_cmd->lun; + r2t_task->CmdSN = lu_cmd->CmdSN; + r2t_task->task_tag = lu_cmd->task_tag; + r2t_task->transfer_len = transfer_len; + r2t_task->transfer_tag = transfer_tag; + + //r2t_task->iobuf = xmalloc(r2t_task->iobufsize); + //memcpy(r2t_task->iobuf, lu_cmd->pdu->data, data_len); + r2t_task->iobufindx = 0; + r2t_task->iobufsize = data_len; + r2t_task->iobuf[0].iov_base = lu_cmd->pdu->data; + r2t_task->iobuf[0].iov_len = data_len; + lu_cmd->pdu->data = NULL; + lu_cmd->pdu->data_segment_len = 0; + + r2t_task->offset = offset; + r2t_task->R2TSN = 0; + r2t_task->DataSN = 0; + r2t_task->F_bit = lu_cmd->F_bit; + + MTX_LOCK(&conn->r2t_mutex); + idx = conn->pending_r2t++; + conn->r2t_tasks[idx] = r2t_task; + MTX_UNLOCK(&conn->r2t_mutex); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Send R2T(Offset=%d, Tag=%x)\n", + r2t_task->offset, r2t_task->transfer_tag); + rc = istgt_iscsi_send_r2t(conn, lu_cmd, + r2t_task->offset, len, r2t_task->transfer_tag, + &r2t_task->R2TSN); + timediff(lu_cmd, 'R', __LINE__); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_send_r2t() failed\n"); + return -1; + } + } + return 0; +} + +static void +istgt_del_transfer_task(CONN_Ptr conn, ISTGT_R2T_TASK_Ptr r2t_task) +{ + int found = 0; + int i, removed = -1; + + if (r2t_task == NULL) + return; + + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t == 0) { + MTX_UNLOCK(&conn->r2t_mutex); + return; + } + for (i = 0; i < conn->pending_r2t; i++) { + if (conn->r2t_tasks[i] == r2t_task) { + removed = i; + found = 1; + break; + } + } + if (found) { + for ( ; i < conn->pending_r2t; i++) { + conn->r2t_tasks[i] = conn->r2t_tasks[i + 1]; + } + conn->pending_r2t--; + conn->r2t_tasks[conn->pending_r2t] = NULL; + } + MTX_UNLOCK(&conn->r2t_mutex); + if (removed != -1) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Removed R2T task conn id=%d, index=%d\n", + conn->id, removed); + } +} + +static void +istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN) +{ + int found = 0; + int i; + + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t == 0) { + MTX_UNLOCK(&conn->r2t_mutex); + return; + } + for (i = 0; i < conn->pending_r2t; i++) { + if (conn->r2t_tasks[i]->CmdSN == CmdSN) { + istgt_free_transfer_task(conn->r2t_tasks[i]); + conn->r2t_tasks[i] = NULL; + found = 1; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Clearing R2T task conn id=%d, index=%d cmdsn:0x%x\n", + conn->id, i, CmdSN); + break; + } + } + if (found) { + for ( ; i < conn->pending_r2t; i++) { + conn->r2t_tasks[i] = conn->r2t_tasks[i + 1]; + } + conn->pending_r2t--; + conn->r2t_tasks[conn->pending_r2t] = NULL; + } + MTX_UNLOCK(&conn->r2t_mutex); +} + +static void +istgt_clear_all_transfer_task(CONN_Ptr conn) +{ + int i; + + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t == 0) { + MTX_UNLOCK(&conn->r2t_mutex); + return; + } + for (i = 0; i < conn->pending_r2t; i++) { + istgt_free_transfer_task(conn->r2t_tasks[i]); + conn->r2t_tasks[i] = NULL; + } + conn->pending_r2t = 0; + MTX_UNLOCK(&conn->r2t_mutex); +} + +static int +istgt_iscsi_op_data(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + ISTGT_R2T_TASK_Ptr r2t_task; + uint8_t *cp; + uint32_t current_task_tag; + uint32_t current_transfer_tag; + uint32_t ExpStatSN; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t ExpDataSN; + uint32_t DataSN; + uint32_t buffer_offset; + size_t data_len; + size_t offset; + int F_bit; + int rc; + int iondx; + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + MTX_LOCK(&conn->r2t_mutex); + if (conn->pending_r2t == 0) { + ISTGT_ERRLOG("No R2T task\n"); + MTX_UNLOCK(&conn->r2t_mutex); + reject_return: + rc = istgt_iscsi_reject(conn, pdu, 0x09); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_reject() failed\n"); + return -1; + } + return 0; + } + MTX_UNLOCK(&conn->r2t_mutex); + + cp = (uint8_t *) &pdu->bhs; + F_bit = BGET8(&cp[1], 7); + data_len = DGET24(&cp[5]); + + task_tag = DGET32(&cp[16]); + transfer_tag = DGET32(&cp[20]); + ExpStatSN = DGET32(&cp[28]); + DataSN = DGET32(&cp[36]); + buffer_offset = DGET32(&cp[40]); + + r2t_task = istgt_get_transfer_task(conn, transfer_tag); + if (r2t_task == NULL) { + ISTGT_ERRLOG("Not found R2T task for transfer_tag=%x (pending_r2t:%d)\n", + transfer_tag, conn->pending_r2t); + goto reject_return; + } + + current_task_tag = r2t_task->task_tag; + current_transfer_tag = r2t_task->transfer_tag; + offset = r2t_task->offset; + ExpDataSN = r2t_task->DataSN; + + if (DataSN != ExpDataSN) { + ISTGT_ERRLOG("DataSN(%x) error\n", DataSN); + return -1; + } + if (task_tag != current_task_tag) { + ISTGT_ERRLOG("task_tag(%x/%x) error\n", + task_tag, current_task_tag); + return -1; + } + if (transfer_tag != current_transfer_tag) { + ISTGT_ERRLOG("transfer_tag(%x/%x) error\n", + transfer_tag, current_transfer_tag); + return -1; + } + if (buffer_offset != offset) { + ISTGT_ERRLOG("offset(%u) error\n", buffer_offset); + return -1; + } + /*if (buffer_offset + data_len > alloc_len) { + ISTGT_ERRLOG("offset error\n"); + return -1; + }*/ + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "copy pdu.data %lu to r2ttask.iobuf at %u; pending r2t=%d, StatSN=%x, ExpStatSN=%x, DataSN=%x\n", + data_len, buffer_offset, conn->pending_r2t, conn->StatSN, ExpStatSN, DataSN); + + iondx = ++r2t_task->iobufindx; + r2t_task->iobufsize += data_len; + offset += data_len; //we do check buffer_offest == offset + r2t_task->iobuf[iondx].iov_base = pdu->data; + r2t_task->iobuf[iondx].iov_len = data_len; + //memcpy(data + buffer_offset, pdu->data, data_len); + pdu->data = NULL; + ExpDataSN++; + + r2t_task->offset = offset; + r2t_task->DataSN = ExpDataSN; + r2t_task->F_bit = F_bit; + return 0; +} + +uint8_t istgt_get_sleep_val(ISTGT_LU_DISK *spec) +{ + int i, val, tot; + val = random() % 100; + tot = 0; + + if(spec->percent_count == 0) + return 0; + + for(i=0;ipercent_count && i<31;i++) + if((tot+spec->percent_val[i]) <= val) + tot += spec->percent_val[i]; + else + break; + + return spec->percent_latency[i]; +} + +static int +istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + int rc; + + /* R2T PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = NULL; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + + rsp[0] = ISCSI_OP_R2T; + BDADD8(&rsp[1], 1, 7); + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], 0); // DataSegmentLength + + DSET64(&rsp[8], lu_cmd->lun); + DSET32(&rsp[16], lu_cmd->task_tag); + DSET32(&rsp[20], transfer_tag); + + DSET32(&rsp[36], *R2TSN); + *R2TSN += 1; + DSET32(&rsp[40], (uint32_t) offset); + DSET32(&rsp[44], (uint32_t) len); + + rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, 0); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "sentR2T sn:%x off:%u len:%u\n", *R2TSN, offset, len); + + return 0; +} + +int +istgt_iscsi_transfer_out(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, size_t transfer_len) +{ + //uint8_t *data = lu_cmd->iobuf; + //size_t alloc_len = lu_cmd->iobufsize; + ISTGT_QUEUE_Ptr r_ptr = NULL; + ISTGT_R2T_TASK_Ptr r2t_task; + ISCSI_PDU data_pdu; + uint8_t *cp; + uint32_t current_task_tag; + uint32_t current_transfer_tag; + uint32_t ExpDataSN; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t ExpStatSN; + uint32_t wCmdSN; + uint32_t DataSN; + uint32_t buffer_offset; + uint32_t R2TSN; + size_t data_len; + size_t segment_len; + size_t first_burst_len; + size_t max_burst_len; + size_t offset; + int opcode; + int F_bit; + int len; + int r2t_flag; + int r2t_sent; + int rc, i; + uint64_t *tptr; + const char *msg; + current_task_tag = lu_cmd->task_tag; + current_transfer_tag = lu_cmd->task_tag; + ExpDataSN = 0; + segment_len = conn->MaxRecvDataSegmentLength; + first_burst_len = conn->FirstBurstLength; + max_burst_len = conn->MaxBurstLength; + offset = 0; + r2t_flag = 0; + r2t_sent = 0; + R2TSN = 0; + + cp = (uint8_t *) &lu_cmd->pdu->bhs; + data_len = DGET24(&cp[5]); + + //if (transfer_len > alloc_len) { + // ISTGT_ERRLOG("transfer_len > alloc_len\n"); + // return -1; + //} + +start: + if(lu_cmd->aborted == 1) + { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d aborted CmdSN:0x%x Transfered=%zd, Offset=%zd\n", + conn->id, lu_cmd->CmdSN, transfer_len, offset); + return 0; + } + + r2t_task = istgt_get_transfer_task(conn, current_transfer_tag); + if (r2t_task != NULL) { + current_task_tag = r2t_task->task_tag; + current_transfer_tag = r2t_task->transfer_tag; + offset = r2t_task->offset; + R2TSN = r2t_task->R2TSN; + ExpDataSN = r2t_task->DataSN; + F_bit = r2t_task->F_bit; + r2t_flag = 1; + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d Using R2T(%x)trtag:%x offset=%zd, DataSN=%x. Transfer=%zd, First=%zd, Max=%zd, Segment=%zd\n", + conn->id, R2TSN, current_transfer_tag, offset, ExpDataSN, + transfer_len, data_len, max_burst_len, segment_len); + + data_len = 0; + + //memcpy(data, r2t_task->iobuf, offset); + lu_cmd->iobufsize = r2t_task->iobufsize; + lu_cmd->iobufindx = r2t_task->iobufindx; + for (i=0; i<=r2t_task->iobufindx; ++i) { + lu_cmd->iobuf[i].iov_base = r2t_task->iobuf[i].iov_base; + lu_cmd->iobuf[i].iov_len = r2t_task->iobuf[i].iov_len; + r2t_task->iobuf[i].iov_base = NULL; + r2t_task->iobuf[i].iov_len = 0; + } + r2t_task->iobufsize = 0; + r2t_task->iobufindx = -1; + istgt_del_transfer_task(conn, r2t_task); + istgt_free_transfer_task(r2t_task); + + rc = istgt_queue_count(&conn->pending_pdus); + if (rc > 0) { + if (g_trace_flag) { + ISTGT_WARNLOG("pending_pdus > 0\n"); + } + } + if (offset < transfer_len) { + if (offset >= (first_burst_len + max_burst_len)) { + /* need more data */ + r2t_flag = 0; + } + len = DMIN32(max_burst_len, + (transfer_len - offset)); + //memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN); + tptr = (uint64_t *)&(data_pdu.bhs); + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + data_pdu.ahs = NULL; + data_pdu.data = NULL; + goto r2t_retry; + } else if (offset == transfer_len) { + if (F_bit == 0) { + ISTGT_ERRLOG("c#%d F_bit not set on the last PDU\n", conn->id); + return -1; + } + } + return 0; + } + + if (data_len != 0) { + if (data_len > first_burst_len) { + ISTGT_ERRLOG("c#%d data_len > first_burst_len, Transfer=%zd, First=%zd, Max=%zd, Segment=%zd\n", + conn->id, transfer_len, data_len, max_burst_len, segment_len); + return -1; + } + if (lu_cmd->pdu->data) { + i = ++lu_cmd->iobufindx; + lu_cmd->iobufsize += data_len; + lu_cmd->iobuf[i].iov_base = lu_cmd->pdu->data; + lu_cmd->iobuf[i].iov_len = data_len; + //memcpy(data + offset, lu_cmd->pdu->data, data_len); + lu_cmd->pdu->data = NULL; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d nothing in R2T, Transfer=%zd, First=%zd, Max=%zd, Segment=%zd\n", + conn->id, transfer_len, data_len, max_burst_len, segment_len); + } + offset += data_len; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d no data in current pdu, or in R2T. Transfer=%zd, First=%zd, Max=%zd, Segment=%zd\n", + conn->id, transfer_len, data_len, max_burst_len, segment_len); + } + + if (offset < transfer_len) { + len = DMIN32(first_burst_len, (transfer_len - offset)); + //memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN); + tptr = (uint64_t *)&(data_pdu.bhs); + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + data_pdu.ahs = NULL; + data_pdu.data = NULL; + do { + + if(lu_cmd->aborted == 1) + goto start; + + /* send R2T if required */ + if (r2t_flag == 0 + && (conn->sess->initial_r2t || offset >= first_burst_len)) { + len = DMIN32(max_burst_len, (transfer_len - offset)); + rc = istgt_iscsi_send_r2t(conn, lu_cmd, + offset, len, current_transfer_tag, &R2TSN); + timediff(lu_cmd, '$', __LINE__); + if (rc < 0) { + ISTGT_ERRLOG("c#%d iscsi_send_r2t() failed\n", conn->id); + goto error_return; + } + r2t_flag = 1; + r2t_sent = 1; + ExpDataSN = 0; + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d TransferIn=%zd, Offset=%zd, Len=%d, sent R2T (should avoid this)\n", + conn->id, transfer_len, offset, len); + } else { + r2t_sent = 0; + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d TransferIn=%zd, Offset=%zd, Len=%d\n", + conn->id, transfer_len, offset, len); + } + + /* transfer by segment_len */ + rc = istgt_iscsi_read_pdu(conn, &data_pdu); + if (rc < 0) { + //ISTGT_ERRLOG("iscsi_read_pdu() failed\n"); + ISTGT_ERRLOG("c#%d iscsi_read_pdu() failed, r2t_sent=%d\n", + conn->id, r2t_sent); + goto error_return; + } + opcode = BGET8W(&data_pdu.bhs.opcode, 5, 6); + + cp = (uint8_t *) &data_pdu.bhs; + F_bit = BGET8(&cp[1], 7); + data_len = DGET24(&cp[5]); + + task_tag = DGET32(&cp[16]); + transfer_tag = DGET32(&cp[20]); + wCmdSN = DGET32(&cp[24]); + ExpStatSN = DGET32(&cp[28]); + DataSN = DGET32(&cp[36]); + buffer_offset = DGET32(&cp[40]); + + /* current tag DATA? */ + msg = NULL; + if (opcode == ISCSI_OP_SCSI_DATAOUT) { + if (task_tag != current_task_tag) { + msg = "not task_tag received"; + } else if (transfer_tag != current_transfer_tag) { + msg = "not transfer_tag received"; + } + if (msg) { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d DATAOUT but %s [tsk:%x tran:%x]", conn->id, msg, task_tag, transfer_tag); + rc = istgt_iscsi_op_data(conn, &data_pdu); + if (rc < 0) { + ISTGT_ERRLOG("c#%d iscsi_op_data() failed\n", conn->id); + goto error_return; + } + if (data_pdu.ahs != NULL) { + xfree(data_pdu.ahs); + data_pdu.ahs = NULL; + } + if (data_pdu.data != NULL) { + xfree(data_pdu.data); + data_pdu.data = NULL; + } + continue; + } + } else { + ISCSI_PDU_Ptr save_pdu; + + rc = istgt_queue_count(&conn->pending_pdus); + if (rc > conn->max_pending) { + ISTGT_ERRLOG("c#%d pending queue(%d) is full\n",conn->id, conn->max_pending); + goto error_return; + } + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "c#%d non DATAOUT PDU, move to pending:%d/%d OP=0x%x cmdsn:0x%x expstatsn:0x%x\n", conn->id, rc, conn->max_pending, opcode, wCmdSN, ExpStatSN); + save_pdu = xmalloc(sizeof *save_pdu); + istgt_iscsi_copy_pdu(save_pdu, &data_pdu); + r_ptr = istgt_queue_enqueue(&conn->pending_pdus, save_pdu); + if (r_ptr == NULL) { + ISTGT_ERRLOG("c#%d queue_enqueue() failed\n", conn->id); + if (save_pdu->ahs != NULL) { + xfree(save_pdu->ahs); + save_pdu->ahs = NULL; + } + if (save_pdu->data != NULL) { + xfree(save_pdu->data); + save_pdu->data = NULL; + } + xfree(save_pdu); + save_pdu = NULL; + goto error_return; + } + data_pdu.ahs = NULL; + data_pdu.data = NULL; + data_pdu.opcode = 0; + continue; + } + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d read_from_net cmdSN=0x%x StatSN=%x, ExpStatSN=%x, DataSN=%x, Offset=%u, Data=%zd\n", + conn->id, wCmdSN, conn->StatSN, ExpStatSN, DataSN, buffer_offset, data_len); + if (DataSN != ExpDataSN) { + ISTGT_ERRLOG("c#%d DataSN(%x) error\n", conn->id, DataSN); + goto error_return; + } +#if 0 + /* not check in DATAOUT */ + if (ExpStatSN != conn->StatSN) { + ISTGT_ERRLOG("StatSN(%u) error\n", + conn->StatSN); + goto error_return; + } +#endif + + if (buffer_offset != offset) { + ISTGT_ERRLOG("c#%d offset(%u) error\n", + conn->id, buffer_offset); + goto error_return; + } + //if (buffer_offset + data_len > alloc_len) { + // ISTGT_ERRLOG("offset error\n"); + // goto error_return; + //} + + timediff(lu_cmd, '@', __LINE__); + i = ++lu_cmd->iobufindx; + lu_cmd->iobufsize += data_len; + lu_cmd->iobuf[i].iov_base = data_pdu.data; + lu_cmd->iobuf[i].iov_len = data_len; + data_pdu.data = NULL; data_pdu.data_segment_len = 0; + //memcpy(data + buffer_offset, data_pdu.data, data_len); + offset += data_len; + len -= data_len; + ExpDataSN++; + + if (r2t_flag == 0 && (offset > first_burst_len)) { + ISTGT_ERRLOG("c#%d data_len(%zd) > first_burst_length(%zd)", + conn->id, offset, first_burst_len); + goto error_return; + } + if (F_bit != 0 && len != 0) { + if (offset < transfer_len) { + r2t_flag = 0; + goto r2t_retry; + } + ISTGT_ERRLOG("c#%d Expecting more data %d\n", conn->id, len); + goto error_return; + } + if (F_bit == 0 && len == 0) { + ISTGT_ERRLOG("c#%d F_bit not set on the last PDU\n", conn->id); + goto error_return; + } + if (len == 0) { + r2t_flag = 0; + } + r2t_retry: + if (data_pdu.ahs == NULL) { + xfree(data_pdu.ahs); + data_pdu.ahs = NULL; + } + if (data_pdu.data != NULL) { + xfree(data_pdu.data); + data_pdu.data = NULL; + } + } while (offset < transfer_len); + + cp = (uint8_t *) &data_pdu.bhs; + F_bit = BGET8(&cp[1], 7); + if (F_bit == 0) { + ISTGT_ERRLOG("c#%d F_bit not set on the last PDU\n", conn->id); + return -1; + } + } else { + cp = (uint8_t *) &lu_cmd->pdu->bhs; + F_bit = BGET8(&cp[1], 7); + if (F_bit == 0) { + ISTGT_ERRLOG("c#%d F_bit not set on the last PDU\n", conn->id); + return -1; + } + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d Transfered=%zd, Offset=%zd\n", + conn->id, transfer_len, offset); + + return 0; + +error_return: + if (data_pdu.ahs != NULL) { + xfree(data_pdu.ahs); + data_pdu.ahs = NULL; + } + if (data_pdu.data != NULL) { + xfree(data_pdu.data); + data_pdu.data = NULL; + } + return -1; +} + +static int +istgt_iscsi_send_nopin(CONN_Ptr conn) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_tag; + int rc; + uint64_t l_isid; + uint16_t l_tsih; + uint32_t s_ExpCmdSN, s_MaxCmdSN; + if (conn->sess == NULL) { + return 0; + } + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + + SESS_MTX_LOCK(conn); + l_isid = conn->sess->isid; + l_tsih = conn->sess->tsih; + s_ExpCmdSN = conn->sess->ExpCmdSN; + s_MaxCmdSN = conn->sess->MaxCmdSN; + SESS_MTX_UNLOCK(conn); + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "send NOPIN isid=%lx, tsih=%u, cid=%u StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x\n", + l_isid, l_tsih, conn->cid, + conn->StatSN, s_ExpCmdSN, s_MaxCmdSN); + + /* without wanting NOPOUT */ + lun = 0; + task_tag = 0xffffffffU; + transfer_tag = 0xffffffffU; + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = NULL; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + rsp[0] = ISCSI_OP_NOPIN; + BDADD8(&rsp[1], 1, 7); + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], 0); // DataSegmentLength + + DSET64(&rsp[8], lun); + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], transfer_tag); + + rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, 0); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + + return 0; +} + +int +istgt_iscsi_send_async(CONN_Ptr conn) +{ + ISCSI_PDU rsp_pdu; + uint8_t *rsp; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_tag; + int rc; + ISTGT_NOTICELOG("SEND ASYNC EVENT for the Initiator"); + + if (conn->sess == NULL) { + return 0; + } + if (!conn->full_feature) { + ISTGT_ERRLOG("before Full Feature\n"); + return -1; + } + + SESS_MTX_LOCK(conn); + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "StatSN=%x, ExpCmdSN=%x, MaxCmdSN=%x\n", + conn->StatSN, conn->sess->ExpCmdSN, + conn->sess->MaxCmdSN); + SESS_MTX_UNLOCK(conn); + + /* without wanting NOPOUT */ + lun = 0; + task_tag = 0xffffffffU; + transfer_tag = 0xffffffffU; + + /* response PDU */ + rsp = (uint8_t *) &rsp_pdu.bhs; + rsp_pdu.data = NULL; + //memset(rsp, 0, ISCSI_BHS_LEN); + uint64_t *tptr = (uint64_t *)rsp; + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; + *(tptr+3) = 0; *(tptr+4) = 0; *(tptr+5) = 0; + rsp[0] = ISCSI_OP_ASYNC; + BDADD8(&rsp[1], 1, 7); + rsp[4] = 0; // TotalAHSLength + DSET24(&rsp[5], 0); // DataSegmentLength + + DSET64(&rsp[8], lun); + DSET32(&rsp[16], task_tag); + DSET32(&rsp[20], transfer_tag); + + rc = istgt_iscsi_write_pdu_upd(conn, &rsp_pdu, 0); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_write_pdu() failed\n"); + return -1; + } + istgt_iscsi_drop_all_conns(conn); + + return 0; +} + +static int +istgt_iscsi_execute(CONN_Ptr conn, ISCSI_PDU_Ptr pdu) +{ + uint8_t opcode; + int rc, ret = 0; + const char *op = "--"; + + if (pdu == NULL) + return -1; + + uint8_t bhsopcode = BGET8W(&pdu->bhs.opcode, 5, 6); + opcode = pdu->opcode; + if (bhsopcode != opcode) { + ISTGT_ERRLOG("opcode changed? (%x->%x), isid=%"PRIx64", tsih=%u, cid=%u\n", + opcode, bhsopcode, conn->isid, conn->tsih, conn->cid); + pdu->opcode = bhsopcode; + opcode = bhsopcode; + } + switch(opcode) { + case ISCSI_OP_NOPOUT: + op = "nopout"; + rc = istgt_iscsi_op_nopout(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_SCSI: + op = "scsi"; + rc = istgt_iscsi_op_scsi(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_TASK: + op = "task"; + rc = istgt_iscsi_op_task(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_LOGIN: + op = "login"; + rc = istgt_iscsi_op_login(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_TEXT: + op = "text"; + rc = istgt_iscsi_op_text(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_LOGOUT: + op = "logout"; + rc = istgt_iscsi_op_logout(conn, pdu); + if (rc < 0) + goto error_out; + ret = 1; + break; + + case ISCSI_OP_SCSI_DATAOUT: + op = "dataout"; + rc = istgt_iscsi_op_data(conn, pdu); + if (rc < 0) + goto error_out; + break; + + case ISCSI_OP_SNACK: + op = "snack"; + default: + ISTGT_ERRLOG("unsupported opcode=%x:%s, isid=%"PRIx64", tsih=%u, cid=%u\n", + opcode, op, conn->isid, conn->tsih, conn->cid); + rc = istgt_iscsi_reject(conn, pdu, 0x04); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_reject() failed\n"); + return -1; + } + break; + } + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "isid=%"PRIx64", tsih=%u, cid=%u, OP=%x:%s done\n", + conn->isid, conn->tsih, conn->cid, opcode, op); + return ret; + + error_out: + + ISTGT_ERRLOG("failed:%d: op:%x:%s, isid=%"PRIx64", tsih=%u, cid=%u\n", + rc, opcode, op, conn->isid, conn->tsih, conn->cid); + return -1; +} + +static void +wait_all_task(CONN_Ptr conn) +{ + ISTGT_LU_TASK_Ptr lu_task; + int kq; + struct kevent kev; + struct timespec kev_timeout; + int msec = 30; + int rc; + + if (conn->running_tasks == 0) { + printf("c#%d running tasks are zero..\n", conn->id); + return; + } + + kq = kqueue(); + if (kq == -1) { + ISTGT_ERRLOG("kqueue() failed\n"); + return; + } + ISTGT_EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return; + } + + /* wait all running tasks */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "waiting task start (%d) (left %d tasks)\n", + conn->id, conn->running_tasks); + while (1) { + kev_timeout.tv_sec = msec; + kev_timeout.tv_nsec = 0; + rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout); + if (rc == -1 && errno == EINTR) { + continue; + } + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + break; + } + if (rc == 0) { + ISTGT_ERRLOG("waiting task timeout (left %d tasks)\n", + conn->running_tasks); + break; + } + + if (kev.ident == (uintptr_t)conn->task_pipe[0]) { + if (kev.flags & (EV_EOF|EV_ERROR)) { + break; + } + char tmp[1]; + + rc = read(conn->task_pipe[0], tmp, 1); + if (rc < 0 || rc == 0 || rc != 1) { + ISTGT_ERRLOG("read() failed\n"); + break; + } + + MTX_LOCK(&conn->task_queue_mutex); + lu_task = istgt_queue_dequeue(&conn->task_queue); + MTX_UNLOCK(&conn->task_queue_mutex); + if (lu_task != NULL) { + if (lu_task->lu_cmd.W_bit) { + /* write */ + if (lu_task->req_transfer_out != 0) { + /* error transfer */ + lu_task->error = 1; + lu_task->abort = 1; + rc = pthread_cond_broadcast(&lu_task->trans_cond); + if (rc != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + /* ignore error */ + } + } else { + if (lu_task->req_execute) { + conn->running_tasks--; + if (conn->running_tasks == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "task cleanup finished\n"); + break; + } + } + /* ignore response */ +#if 0 + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + /* ignore error */ + } +#endif + } + } else { + /* read or no data */ + /* ignore response */ +#if 0 + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + /* ignore error */ + } +#endif + } + } else { + ISTGT_ERRLOG("lu_task is NULL\n"); + break; + } + } + } + + istgt_clear_all_transfer_task(conn); + close(kq); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "waiting task end (%d) (left %d tasks)\n", + conn->id, conn->running_tasks); +} + + +static void +snd_cleanup(void *arg) +{ + ISTGT_WARNLOG("snd:%p thread_exit\n", arg); +} + +static void +worker_cleanup(void *arg) +{ + CONN_Ptr conn = (CONN_Ptr) arg; + ISTGT_LU_Ptr lu; + int rc; + + ISTGT_WARNLOG("conn:%d/%d/%d %s/%s cleanup", conn->id, conn->kq, ntohs(conn->iport), conn->thr, conn->sthr); + + /* cleanup */ + pthread_mutex_unlock(&conn->task_queue_mutex); + pthread_mutex_unlock(&conn->result_queue_mutex); + if (conn->sess != NULL) { + if (conn->sess->lu != NULL) { + pthread_mutex_unlock(&conn->sess->lu->mutex); + } + pthread_mutex_unlock(&conn->sess->mutex); + } + if (conn->exec_lu_task != NULL) { + conn->exec_lu_task->error = 1; + pthread_cond_broadcast(&conn->exec_lu_task->trans_cond); + pthread_mutex_unlock(&conn->exec_lu_task->trans_mutex); + } + pthread_mutex_unlock(&conn->wpdu_mutex); + pthread_mutex_unlock(&conn->r2t_mutex); + pthread_mutex_unlock(&conn->istgt->mutex); + pthread_mutex_unlock(&g_conns_mutex); + pthread_mutex_unlock(&g_last_tsih_mutex); + + conn->state = CONN_STATE_EXITING; + if (conn->sess != NULL) { + lu = conn->sess->lu; + if(lu != NULL) + MTX_LOCK(&lu->mutex); + SESS_MTX_LOCK(conn); + if (lu != NULL && lu->queue_depth != 0) { + rc = istgt_lu_clear_task_IT(conn, lu); + if (rc < 0) { + ISTGT_ERRLOG("lu_clear_task_IT() failed\n"); + } + istgt_clear_all_transfer_task(conn); + } + SESS_MTX_UNLOCK(conn); + if(lu != NULL) + MTX_UNLOCK(&lu->mutex); + } + if (conn->pdu.ahs != NULL) { + xfree(conn->pdu.ahs); + conn->pdu.ahs = NULL; + } + if (conn->pdu.data != NULL) { + xfree(conn->pdu.data); + conn->pdu.data = NULL; + } + wait_all_task(conn); + + MTX_LOCK(&conn->result_queue_mutex); + pthread_cond_broadcast(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + pthread_join(conn->sender_thread, NULL); + close(conn->sock); + close(conn->kq); + conn->kq = -1; +#if 0 + sleep(1); +#endif + + /* cleanup conn & sess */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup LOCK\n"); + while(conn->inflight != 0) + sleep(1); + sleep(5); + MTX_LOCK(&g_conns_mutex); + g_conns[conn->id] = NULL; + istgt_remove_conn(conn); + MTX_UNLOCK(&g_conns_mutex); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup UNLOCK\n"); + + return; +} + +const char lu_task_typ[4][12] = { + "RESPONSE", + "REQPDU", + "REQUPDPDU", + "unknown" +}; + +int g_logtimes = 0; +uint64_t g_logdelayns = 50000000; //50ms +extern char scsi_ops[SCSI_ARYSZ + 1][20]; + +static inline void +prof_log(ISTGT_LU_CMD_Ptr p, const char *caller) +{ + if (p == NULL) + return; + int ind = 0; + uint64_t len = 0; + uint64_t x = 1; + int base = 0, i, levels; + int baseindx = (base >=0 || base < _PSZ) ? base : 0; + int _inx = p->_andx; + struct timespec *_s = &(p->times[baseindx]); + struct timespec *_n = &(p->times[_inx]); + struct timespec _r; + ISTGT_LU_DISK *spec; + unsigned long secs, nsecs; + + if ((_n->tv_nsec - _s->tv_nsec) < 0) { + _r.tv_sec = _n->tv_sec - _s->tv_sec-1; + _r.tv_nsec = 1000000000 + _n->tv_nsec - _s->tv_nsec; + } else { + _r.tv_sec = _n->tv_sec - _s->tv_sec; + _r.tv_nsec = _n->tv_nsec - _s->tv_nsec; + } + spec = NULL; + if(p->lu) { + spec = p->lu->lun[0].spec; + if(spec != NULL) { + if(p->lblen > 0) { + len = (p->lblen * spec->blocklen)/ 1024; + for(; (x < len && ind < 9); x *= 2, ind++); + } + else + ind = 0; + switch(p->cdb0) { + case SBC_WRITE_6: + case SBC_WRITE_10: + case SBC_WRITE_12: + case SBC_WRITE_16: + case SBC_WRITE_AND_VERIFY_10: + case SBC_WRITE_AND_VERIFY_12: + case SBC_WRITE_AND_VERIFY_16: + if((spec->IO_size[ind].write.total_time.tv_sec < _r.tv_sec) || (spec->IO_size[ind].write.total_time.tv_sec == _r.tv_sec && spec->IO_size[ind].write.total_time.tv_nsec < _r.tv_nsec)) { + spec->IO_size[ind].write.total_time.tv_sec = _r.tv_sec; + spec->IO_size[ind].write.total_time.tv_nsec = _r.tv_nsec; + spec->IO_size[ind].write.lba = p->lba; + spec->IO_size[ind].write.lblen = p->lblen; + for(i = 1; i < _PSZ ; i++) { + spec->IO_size[ind].write.caller[i] = p->caller[i]; + spec->IO_size[ind].write.tdiff[i].tv_sec = p->tdiff[i].tv_sec; + spec->IO_size[ind].write.tdiff[i].tv_nsec = p->tdiff[i].tv_nsec; + } + } + break; + case SBC_READ_6: + case SBC_READ_10: + case SBC_READ_12: + case SBC_READ_16: + if((spec->IO_size[ind].read.total_time.tv_sec < _r.tv_sec) || (spec->IO_size[ind].read.total_time.tv_sec == _r.tv_sec && spec->IO_size[ind].read.total_time.tv_nsec < _r.tv_nsec)) { + spec->IO_size[ind].read.total_time.tv_sec = _r.tv_sec; + spec->IO_size[ind].read.total_time.tv_nsec = _r.tv_nsec; + spec->IO_size[ind].read.lba = p->lba; + spec->IO_size[ind].read.lblen = p->lblen; + for(i = 1; i < _PSZ ; i++) { + spec->IO_size[ind].read.caller[i] = p->caller[i]; + spec->IO_size[ind].read.tdiff[i].tv_sec = p->tdiff[i].tv_sec; + spec->IO_size[ind].read.tdiff[i].tv_nsec = p->tdiff[i].tv_nsec; + } + } + break; + case SBC_COMPARE_AND_WRITE: + if((spec->IO_size[ind].cmp_n_write.total_time.tv_sec < _r.tv_sec) || (spec->IO_size[ind].cmp_n_write.total_time.tv_sec == _r.tv_sec && spec->IO_size[ind].cmp_n_write.total_time.tv_nsec < _r.tv_nsec)) { + spec->IO_size[ind].cmp_n_write.total_time.tv_sec = _r.tv_sec; + spec->IO_size[ind].cmp_n_write.total_time.tv_nsec = _r.tv_nsec; + spec->IO_size[ind].cmp_n_write.lba = p->lba; + spec->IO_size[ind].cmp_n_write.lblen = p->lblen; + for(i = 1; i < _PSZ ; i++) { + spec->IO_size[ind].cmp_n_write.caller[i] = p->caller[i]; + spec->IO_size[ind].cmp_n_write.tdiff[i].tv_sec = p->tdiff[i].tv_sec; + spec->IO_size[ind].cmp_n_write.tdiff[i].tv_nsec = p->tdiff[i].tv_nsec; + } + } + break; + case SBC_UNMAP: + if((spec->IO_size[ind].unmp.total_time.tv_sec < _r.tv_sec) || (spec->IO_size[ind].unmp.total_time.tv_sec == _r.tv_sec && spec->IO_size[ind].unmp.total_time.tv_nsec < _r.tv_nsec)) { + spec->IO_size[ind].unmp.total_time.tv_sec = _r.tv_sec; + spec->IO_size[ind].unmp.total_time.tv_nsec = _r.tv_nsec; + spec->IO_size[ind].unmp.lba = p->lba; + spec->IO_size[ind].unmp.lblen = p->lblen; + for(i = 1; i < _PSZ ; i++) { + spec->IO_size[ind].unmp.caller[i] = p->caller[i]; + spec->IO_size[ind].unmp.tdiff[i].tv_sec = p->tdiff[i].tv_sec; + spec->IO_size[ind].unmp.tdiff[i].tv_nsec = p->tdiff[i].tv_nsec; + } + } + break; + case SBC_WRITE_SAME_10: + case SBC_WRITE_SAME_16: + if((spec->IO_size[ind].write_same.total_time.tv_sec < _r.tv_sec) || (spec->IO_size[ind].write_same.total_time.tv_sec == _r.tv_sec && spec->IO_size[ind].write_same.total_time.tv_nsec < _r.tv_nsec)) { + spec->IO_size[ind].write_same.total_time.tv_sec = _r.tv_sec; + spec->IO_size[ind].write_same.total_time.tv_nsec = _r.tv_nsec; + spec->IO_size[ind].write_same.lba = p->lba; + spec->IO_size[ind].write_same.lblen = p->lblen; + for(i = 1; i < _PSZ ; i++) { + spec->IO_size[ind].write_same.caller[i] = p->caller[i]; + spec->IO_size[ind].write_same.tdiff[i].tv_sec = p->tdiff[i].tv_sec; + spec->IO_size[ind].write_same.tdiff[i].tv_nsec = p->tdiff[i].tv_nsec; + } + } + break; + } + } + } + levels = 8; + if(unlikely(spec != NULL && spec->do_avg == 1)) + { + //if(p->caller[1] == 'q' && p->caller[2] == 'w' && p->caller[3] == 'D' && p->caller[4] == 'r' && p->caller[5] == 's') + if(p->caller[2] == '1' && p->caller[3] == 'q' && p->caller[4] == 'w' && p->caller[5] == 'D' && p->caller[6] == 'r' && p->caller[7] == 's') + { + for(i=2; iavgs[i].count++; + spec->avgs[i].tot_sec += p->tdiff[i].tv_sec; + spec->avgs[i].tot_nsec += p->tdiff[i].tv_nsec; + secs = spec->avgs[i].tot_nsec/1000000000; + nsecs = spec->avgs[i].tot_nsec%1000000000; + spec->avgs[i].tot_sec += secs; + spec->avgs[i].tot_nsec = nsecs; + } + } + { + spec->avgs[levels].count++; + spec->avgs[levels].tot_sec += (_r.tv_sec); + spec->avgs[levels].tot_nsec += (_r.tv_nsec); + secs = spec->avgs[levels].tot_nsec/1000000000; + nsecs = spec->avgs[levels].tot_nsec%1000000000; + spec->avgs[levels].tot_sec += secs; + spec->avgs[levels].tot_nsec = nsecs; + } +/* + levels++; + spec->avgs[levels].count += istgt_queue_count(&spec->cmd_queue); + levels++; + spec->avgs[levels].count += istgt_queue_count(&spec->blocked_queue); + levels++; + levels++; + spec->avgs[levels].count += spec->inflight; +*/ + } + + if (g_logtimes == 1 && (_r.tv_sec || (_r.tv_nsec > (long)g_logdelayns))) { + syslog(LOG_NOTICE, "%-20.20s: %-4.4s: LU%d: CSN:0x%x TT:%x OP:%2.2x:%x:%s:%s(%lu+%u)" + " %lds.%9.9ldns [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld" + " %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]%d flags:0x%x", + tinfo, caller, p->lunum, p->CmdSN, p->task_tag, p->cdb0, p->status, + scsi_ops[istgt_cmd_table[p->cdb0].statidx], p->info, p->lba, p->lblen, + _r.tv_sec, _r.tv_nsec, + p->caller[1] ? p->caller[1] : '9', p->tdiff[1].tv_sec, p->tdiff[1].tv_nsec, + p->caller[2] ? p->caller[2] : '9', p->tdiff[2].tv_sec, p->tdiff[2].tv_nsec, + p->caller[3] ? p->caller[3] : '9', p->tdiff[3].tv_sec, p->tdiff[3].tv_nsec, + p->caller[4] ? p->caller[4] : '9', p->tdiff[4].tv_sec, p->tdiff[4].tv_nsec, + p->caller[5] ? p->caller[5] : '9', p->tdiff[5].tv_sec, p->tdiff[5].tv_nsec, + p->caller[6] ? p->caller[6] : '9', p->tdiff[6].tv_sec, p->tdiff[6].tv_nsec, + p->caller[7] ? p->caller[7] : '9', p->tdiff[7].tv_sec, p->tdiff[7].tv_nsec, + p->caller[8] ? p->caller[8] : '9', p->tdiff[8].tv_sec, p->tdiff[8].tv_nsec, + p->_roll_cnt, p->flags); + } else if (g_trace_flag & (ISTGT_TRACE_ISCSI | ISTGT_TRACE_PROF | ISTGT_TRACE_PROFX)) { + if (_r.tv_sec == 0 && _r.tv_nsec < 8000000) { + if (g_trace_flag & ISTGT_TRACE_PROFX) + syslog(LOG_NOTICE, "%-20.20s: %-4.4s: LU%d: CSN:0x%x TT:%x OP:%2.2x:%x:%s:%s(%lu+%u)" + "%ldns [%c %c %c %c %c %c %c %c]%d flags:0x%x", + tinfo, caller, p->lunum, p->CmdSN, p->task_tag, p->cdb0, p->status, + scsi_ops[istgt_cmd_table[p->cdb0].statidx], p->info, p->lba, p->lblen, + _r.tv_nsec, + p->caller[1] ? p->caller[1] : '9', p->caller[2] ? p->caller[2] : '9', + p->caller[3] ? p->caller[3] : '9', p->caller[4] ? p->caller[4] : '9', + p->caller[5] ? p->caller[5] : '9', p->caller[6] ? p->caller[6] : '9', + p->caller[7] ? p->caller[7] : '9', p->caller[8] ? p->caller[8] : '9', + p->_roll_cnt, p->flags); + } else { + syslog(LOG_NOTICE, "%-20.20s: %-4.4s: LU%d: CSN:0x%x TT:%x OP:%2.2x:%x:%s:%s(%lu+%u)" + " %lds.%9.9ldns [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld" + " %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]%d flags:0x%x", + tinfo, caller, p->lunum, p->CmdSN, p->task_tag, p->cdb0, p->status, + scsi_ops[istgt_cmd_table[p->cdb0].statidx], p->info, p->lba, p->lblen, + _r.tv_sec, _r.tv_nsec, + p->caller[1] ? p->caller[1] : '9', p->tdiff[1].tv_sec, p->tdiff[1].tv_nsec, + p->caller[2] ? p->caller[2] : '9', p->tdiff[2].tv_sec, p->tdiff[2].tv_nsec, + p->caller[3] ? p->caller[3] : '9', p->tdiff[3].tv_sec, p->tdiff[3].tv_nsec, + p->caller[4] ? p->caller[4] : '9', p->tdiff[4].tv_sec, p->tdiff[4].tv_nsec, + p->caller[5] ? p->caller[5] : '9', p->tdiff[5].tv_sec, p->tdiff[5].tv_nsec, + p->caller[6] ? p->caller[6] : '9', p->tdiff[6].tv_sec, p->tdiff[6].tv_nsec, + p->caller[7] ? p->caller[7] : '9', p->tdiff[7].tv_sec, p->tdiff[7].tv_nsec, + p->caller[8] ? p->caller[8] : '9', p->tdiff[8].tv_sec, p->tdiff[8].tv_nsec, + p->_roll_cnt, p->flags); + } + } +} + +static void * +sender(void *arg) +{ + CONN_Ptr conn = (CONN_Ptr) arg; + ISTGT_LU_TASK_Ptr lu_task; + struct timespec abstime; + time_t now; + int rc; + ISCSI_PDU_Ptr pdu = NULL; + pthread_t slf = pthread_self(); + snprintf(tinfo , sizeof tinfo, "s#%d.%ld.%d", conn->id, (uint64_t)(((uint64_t *)slf)[0]), ntohs(conn->iport)); +#ifdef HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(slf, tinfo); +#endif + + pthread_cleanup_push(snd_cleanup, (void *)conn); + memset(&abstime, 0, sizeof abstime); + /* handle DATA-IN/SCSI status */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sender loop start (%d)\n", conn->id); + //MTX_LOCK(&conn->sender_mutex); + while (1) { + if (conn->state != CONN_STATE_RUNNING) { + break; + } + MTX_LOCK(&conn->result_queue_mutex); + dequeue_result_queue: + lu_task = istgt_queue_dequeue(&conn->result_queue); + if (lu_task == NULL) { + conn->sender_waiting = 1; + now = time(NULL); + abstime.tv_sec = now + conn->timeout; + abstime.tv_nsec = 0; + rc = pthread_cond_timedwait(&conn->result_queue_cond, + &conn->result_queue_mutex, &abstime); + conn->sender_waiting = 0; + if (rc == ETIMEDOUT) { + /* nothing */ + } + if (conn->state != CONN_STATE_RUNNING) { + MTX_UNLOCK(&conn->result_queue_mutex); + break; + } else { + goto dequeue_result_queue; + } + } + if(lu_task->lu_cmd.aborted == 1 || lu_task->lu_cmd.release_aborted == 1) + { + ISTGT_LOG("Aborted from result queue\n"); + MTX_UNLOCK(&conn->result_queue_mutex); + rc = istgt_lu_destroy_task(lu_task); + if(rc < 0) + ISTGT_ERRLOG("lu_destroy_task failed\n"); + continue; + } + + lu_task->lu_cmd.flags |= ISTGT_RESULT_Q_DEQUEUED; + MTX_UNLOCK(&conn->result_queue_mutex); + /* send all responses */ +// MTX_LOCK(&conn->wpdu_mutex); + do { + lu_task->lu_cmd.flags |= ISTGT_RESULT_Q_DEQUEUED; + if(lu_task->lu_cmd.aborted == 1) + { + ISTGT_LOG("Aborted from result queue\n"); + rc = istgt_lu_destroy_task(lu_task); + if(rc < 0) + ISTGT_ERRLOG("lu_destroy_task failed\n"); + break; + } + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "CSN:%x sender type:%d 0x%x.%lu+%u", + lu_task->lu_cmd.CmdSN, lu_task->type, + lu_task->lu_cmd.cdb0, lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen); + lu_task->lock = 1; + timediff(&lu_task->lu_cmd, 'r', __LINE__); + if (lu_task->type == ISTGT_LU_TASK_RESPONSE) { + /* send DATA-IN, SCSI status */ + rc = istgt_iscsi_task_response(conn, lu_task); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG( + "iscsi_task_response() CSN=%x failed" + " on %s(%s)\n", lu_task->lu_cmd.CmdSN, + conn->target_port, conn->initiator_port); + rc = write(conn->task_pipe[1], "E", 1); + if(rc < 0 || rc != 1) { + ISTGT_ERRLOG("write() failed\n"); + } + break; + } + timediff(&lu_task->lu_cmd, 's', __LINE__); + prof_log(&lu_task->lu_cmd, "resp"); + if(lu_task->complete_queue_ptr != NULL) + ISTGT_ERRLOG("complete_queue_ptr not NULL\n"); + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + break; + } + } else if (lu_task->type == ISTGT_LU_TASK_REQPDU) { + reqpdu: + pdu = lu_task->lu_cmd.pdu; + /* send PDU */ + rc = istgt_iscsi_write_pdu_internal(lu_task->conn, + lu_task->lu_cmd.pdu); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG( + "iscsi_write_pdu() failed on %s(%s)\n", + lu_task->conn->target_port, + lu_task->conn->initiator_port); + rc = write(conn->task_pipe[1], "E", 1); + if(rc < 0 || rc != 1) { + ISTGT_ERRLOG("write() failed\n"); + } + break; + } + /* free allocated memory by caller */ + timediff(&lu_task->lu_cmd, 'S', __LINE__); + prof_log(&lu_task->lu_cmd, + (lu_task->type == ISTGT_LU_TASK_REQUPDPDU) ? "requ" : "req "); + if (pdu->data != NULL) { + xfree(pdu->data); + pdu->data = NULL; + } + if (pdu->ahs != NULL) { + xfree(pdu->ahs); + pdu->ahs = NULL; + } + if (lu_task->lu_cmd.data != NULL) { + xfree(lu_task->lu_cmd.data); + lu_task->lu_cmd.data = NULL; + } + if (lu_task->lu_cmd.sense_data != NULL) { + xfree(lu_task->lu_cmd.sense_data); + lu_task->lu_cmd.sense_data = NULL; + } + xfree(lu_task); + } else if (lu_task->type == ISTGT_LU_TASK_REQUPDPDU) { + rc = istgt_update_pdu(lu_task->conn, &lu_task->lu_cmd); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG( + "update_pdu() failed on %s(%s)\n", + lu_task->conn->target_port, + lu_task->conn->initiator_port); + rc = write(conn->task_pipe[1], "E", 1); + if(rc < 0 || rc != 1) { + ISTGT_ERRLOG("write() failed\n"); + } + break; + } + goto reqpdu; + } else { + ISTGT_ERRLOG("Unknown task type %x\n", lu_task->type); + rc = -1; + } + // conn is running? + if (conn->state != CONN_STATE_RUNNING) { + //ISTGT_WARNLOG("exit thread\n"); + break; + } + MTX_LOCK(&conn->result_queue_mutex); + lu_task = istgt_queue_dequeue(&conn->result_queue); + MTX_UNLOCK(&conn->result_queue_mutex); + } while (lu_task != NULL); +// MTX_UNLOCK(&conn->wpdu_mutex); + } + //MTX_UNLOCK(&conn->sender_mutex); + pthread_cleanup_pop(0); + ISTGT_NOTICELOG("sender loop ended (%d:%d:%d)\n", conn->id, conn->kq, ntohs(conn->iport)); + return NULL; +} + + +static void * +worker(void *arg) +{ + CONN_Ptr conn = (CONN_Ptr) arg; + ISTGT_LU_TASK_Ptr lu_task; + ISTGT_LU_Ptr lu; + ISCSI_PDU_Ptr pdu; + sigset_t signew, sigold; + int kq; + struct kevent kev; + struct timespec kev_timeout; + int rc; + + pthread_t slf = pthread_self(); + snprintf(tinfo , sizeof tinfo, "c#%d.%ld.%d", conn->id, (uint64_t)(((uint64_t *)slf)[0]), ntohs(conn->iport)); +#ifdef HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(slf, tinfo); +#endif + + kq = kqueue(); + if (kq == -1) { + ISTGT_ERRLOG("kqueue() failed\n"); + return NULL; + } + ISTGT_NOTICELOG("con:%d/%d [%x:%d->%s:%s,%d]", + conn->id, kq, conn->iaddr, ntohs(conn->iport), + conn->portal.host, conn->portal.port, conn->portal.tag); + conn->kq = kq; +#if defined (ISTGT_USE_IOVEC) && defined (NOTE_LOWAT) + ISTGT_EV_SET(&kev, conn->sock, EVFILT_READ, EV_ADD, NOTE_LOWAT, ISCSI_BHS_LEN, NULL); +#else + ISTGT_EV_SET(&kev, conn->sock, EVFILT_READ, EV_ADD, 0, 0, NULL); +#endif + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return NULL; + } + ISTGT_EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return NULL; + } + + if (!conn->istgt->daemon) { + ISTGT_EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return NULL; + } + ISTGT_EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + rc = kevent(kq, &kev, 1, NULL, 0, NULL); + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + close(kq); + return NULL; + } + } + + conn->pdu.ahs = NULL; + conn->pdu.data = NULL; + conn->state = CONN_STATE_RUNNING; + conn->exec_lu_task = NULL; + lu_task = NULL; + + pthread_cleanup_push(worker_cleanup, conn); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + /* create sender thread */ + rc = pthread_create(&conn->sender_thread, &conn->istgt->attr, + &sender, (void *)conn); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed\n"); + goto cleanup_exit; + } + snprintf(conn->sthr, sizeof conn->sthr, "s#%d.%ld.%d", conn->id, (uint64_t)(((uint64_t *)(conn->sender_thread))[0]), ntohs(conn->iport)); + conn->wsock = conn->sock; + + sigemptyset(&signew); + sigemptyset(&sigold); + sigaddset(&signew, ISTGT_SIGWAKEUP); + pthread_sigmask(SIG_UNBLOCK, &signew, &sigold); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "reader start (%d:%d) %s/%s\n", conn->id, conn->kq, conn->thr, conn->sthr); + while (1) { + /* check exit request */ + if (conn->sess != NULL) { + SESS_MTX_LOCK(conn); + lu = conn->sess->lu; + SESS_MTX_UNLOCK(conn); + } else { + lu = NULL; + } + if (lu != NULL) { + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) { + conn->state = CONN_STATE_EXITING; + break; + } + } else { + if (istgt_get_state(conn->istgt) != ISTGT_STATE_RUNNING) { + conn->state = CONN_STATE_EXITING; + break; + } + } + + pthread_testcancel(); + if (conn->state != CONN_STATE_RUNNING) { + break; + } + + //ISTGT_TRACELOG(ISTGT_TRACE_NET, + // "kevent sock %d (timeout %dms)\n", + // conn->sock, conn->nopininterval); + if (conn->nopininterval != 0) { + kev_timeout.tv_sec = conn->nopininterval / 1000; + kev_timeout.tv_nsec = (conn->nopininterval % 1000) * 1000000; + } else { + kev_timeout.tv_sec = DEFAULT_NOPININTERVAL; + kev_timeout.tv_nsec = 0; + } + rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout); + if (rc == -1 && errno == EINTR) { + //ISTGT_ERRLOG("EINTR kevent\n"); + continue; + } + if (rc == -1) { + ISTGT_ERRLOG("kevent() failed\n"); + break; + } + if (rc == 0) { + /* idle timeout, send diagnosis packet */ + if (conn->nopininterval != 0) { + rc = istgt_iscsi_send_nopin(conn); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_send_nopin() failed\n"); + break; + } + } + continue; + } + if (kev.filter == EVFILT_SIGNAL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n"); + if (kev.ident == SIGINT || kev.ident == SIGTERM) { + ISTGT_ERRLOG("Kevent Signal %s errno %d", (kev.ident == SIGINT) ? "SIGINT" : "SIGTERM", errno); + break; + } + continue; + } + + /* on socket */ + if (kev.ident == (uintptr_t)conn->sock) { + if (kev.flags & (EV_EOF|EV_ERROR)) { + ISTGT_ERRLOG( + "kevent %s errno %d\n", (kev.flags & EV_EOF) ? "EV_EOF" : "EV_ERROR", errno); + break; + } + rc = istgt_iscsi_read_pdu(conn, &conn->pdu); + if (rc < 0) { + if (conn->state != CONN_STATE_EXITING) { + ISTGT_ERRLOG("conn->state = %d\n", conn->state); + } + if (conn->state != CONN_STATE_RUNNING) { + if (errno == EINPROGRESS) { + sleep(1); + continue; + } + if (errno == ECONNRESET + || errno == ETIMEDOUT) { + ISTGT_ERRLOG( + "iscsi_read_pdu() RESET/TIMEOUT errno %d\n", errno); + } else { + ISTGT_ERRLOG( + "iscsi_read_pdu() EOF\n"); + } + break; + } + ISTGT_ERRLOG("iscsi_read_pdu() failed %d conn-state:%d\n", rc, conn->state); + break; + } + execute_pdu: + if (conn->state != CONN_STATE_RUNNING) { + break; + } + + rc = istgt_iscsi_execute(conn, &conn->pdu); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_execute() failed on %s(%s)\n", + conn->target_port, conn->initiator_port); + break; + } else if (rc == 1) { //means successful logout ISCSI_OP_LOGOUT + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "logout received\n"); + break; + } + + if (conn->pdu.ahs != NULL) { + xfree(conn->pdu.ahs); + conn->pdu.ahs = NULL; + } + if (conn->pdu.data != NULL) { + xfree(conn->pdu.data); + conn->pdu.data = NULL; + } + + /* execute pending PDUs */ + pdu = istgt_queue_dequeue(&conn->pending_pdus); + if (pdu != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "execute pending PDU\n"); + istgt_iscsi_copy_pdu(&conn->pdu, pdu); + xfree(pdu); + goto execute_pdu; + } + +#if 0 + /* retry read/PDUs */ + continue; +#endif + } + + /* execute on task queue */ + if (kev.ident == (uintptr_t)conn->task_pipe[0]) { + if (kev.flags & (EV_EOF|EV_ERROR)) { + ISTGT_ERRLOG( + "kevent EOF/ERROR kev.flags %s errno %d\n", (kev.flags & EV_EOF) ? "EV_EOF" : "EV_ERROR", errno); + break; + } + char tmp[1]; + + //ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Queue Task START\n"); + + rc = read(conn->task_pipe[0], tmp, 1); + if (rc < 0 || rc == 0 || rc != 1) { + ISTGT_ERRLOG("read() failed rc:%d (con:%d)\n", rc, conn->id); + break; + } + if (tmp[0] == 'E') { + ISTGT_NOTICELOG("exit request (%d)\n", conn->id); + break; + } + + /* DATA-IN/OUT */ + MTX_LOCK(&conn->task_queue_mutex); + rc = istgt_queue_count(&conn->task_queue); + lu_task = istgt_queue_dequeue(&conn->task_queue); + MTX_UNLOCK(&conn->task_queue_mutex); + if (lu_task != NULL) { + if (conn->exec_lu_task != NULL) { + ISTGT_ERRLOG("task is overlapped (CSN=%x, %x)\n", + conn->exec_lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.CmdSN); + break; + } + conn->exec_lu_task = lu_task; + if (lu_task->lu_cmd.W_bit) { + /* write */ + if (lu_task->req_transfer_out == 0) { + if (lu_task->req_execute) { + if (conn->running_tasks > 0) { + conn->running_tasks--; + } else { + ISTGT_ERRLOG("running no task\n"); + } + } + rc = istgt_iscsi_task_response(conn, lu_task); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n", + conn->target_port, + conn->initiator_port); + break; + } +#if 0 + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + break; + } +#endif + lu_task = NULL; + conn->exec_lu_task = NULL; + } else { + //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Task Write Trans START\n"); + rc = istgt_iscsi_transfer_out(conn, &(lu_task->lu_cmd), + lu_task->lu_cmd.transfer_len); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG("iscsi_task_transfer_out() failed on %s(%s)\n", + conn->target_port, + conn->initiator_port); + break; + } + //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Task Write Trans END\n"); + + MTX_LOCK(&lu_task->trans_mutex); + lu_task->req_transfer_out = 0; + + /* need response after execution */ + lu_task->req_execute = 1; + + rc = pthread_cond_broadcast(&lu_task->trans_cond); + MTX_UNLOCK(&lu_task->trans_mutex); + if (rc != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + break; + } + lu_task = NULL; + conn->exec_lu_task = NULL; + } + } else { + /* read or no data */ + rc = istgt_iscsi_task_response(conn, lu_task); + if (rc < 0) { + lu_task->error = 1; + ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n", + conn->target_port, + conn->initiator_port); + break; + } +#if 0 + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + break; + } +#endif + lu_task = NULL; + conn->exec_lu_task = NULL; + } + } + /* XXX PDUs in DATA-OUT? */ + pdu = istgt_queue_dequeue(&conn->pending_pdus); + if (pdu != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "pending in task\n"); + istgt_iscsi_copy_pdu(&conn->pdu, pdu); + xfree(pdu); + kev.ident = -1; + goto execute_pdu; + } + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended (%d)\n", conn->id); + + cleanup_exit: + ; + pthread_cleanup_pop(0); + conn->state = CONN_STATE_EXITING; + if (conn->sess != NULL) { + lu = conn->sess->lu; + if(lu != NULL) + MTX_LOCK(&lu->mutex); + SESS_MTX_LOCK(conn); + rc = 0; + if (lu != NULL && lu->queue_depth != 0) { + rc = istgt_lu_clear_task_IT(conn, lu); + istgt_clear_all_transfer_task(conn); + } + SESS_MTX_UNLOCK(conn); + if(lu != NULL) + MTX_UNLOCK(&lu->mutex); + if (rc < 0) { + ISTGT_ERRLOG("lu_clear_task_IT() failed\n"); + } + } + if (conn->pdu.ahs != NULL) { + xfree(conn->pdu.ahs); + conn->pdu.ahs = NULL; + } + if (conn->pdu.data != NULL) { + xfree(conn->pdu.data); + conn->pdu.data = NULL; + } + wait_all_task(conn); + + + if (1) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "stop sender thread (%d)\n", conn->id); + /* stop sender thread */ + MTX_LOCK(&conn->result_queue_mutex); + rc = pthread_cond_broadcast(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + if (rc != 0) { + ISTGT_ERRLOG("cond_broadcast() failed\n"); + /* ignore errors */ + } + rc = pthread_join(conn->sender_thread, NULL); + if (rc != 0) { + ISTGT_ERRLOG("pthread_join() failed\n"); + /* ignore errors */ + } + } + + close(conn->sock); + close(kq); + conn->kq = -1; +#if 0 + sleep(1); +#endif + ISTGT_NOTICELOG("worker %d/%d/%d end (%s/%s)", conn->id, conn->kq, ntohs(conn->iport), conn->thr, conn->sthr); + + /* cleanup conn & sess */ + while(conn->inflight != 0) + sleep(1); + sleep(5); + MTX_LOCK(&g_conns_mutex); + g_conns[conn->id] = NULL; + istgt_remove_conn(conn); + MTX_UNLOCK(&g_conns_mutex); + return NULL; +} + +int +istgt_create_conn(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen __attribute__((__unused__))) +{ + char buf[MAX_TMPBUF]; + CONN_Ptr conn; + int rc; + int i; + + conn = xmalloc(sizeof *conn); + memset(conn, 0, sizeof *conn); + + conn->istgt = istgt; + MTX_LOCK(&istgt->mutex); + conn->timeout = istgt->timeout; + conn->nopininterval = istgt->nopininterval; + conn->nopininterval *= 1000; /* sec. to msec. */ + conn->max_r2t = istgt->maxr2t; + conn->TargetMaxRecvDataSegmentLength = istgt->MaxRecvDataSegmentLength; + MTX_UNLOCK(&istgt->mutex); + conn->MaxRecvDataSegmentLength = 8192; // RFC3720(12.12) + if (conn->TargetMaxRecvDataSegmentLength + < conn->MaxRecvDataSegmentLength) { + conn->TargetMaxRecvDataSegmentLength + = conn->MaxRecvDataSegmentLength; + } + conn->MaxOutstandingR2T = 1; + conn->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH; + conn->MaxBurstLength = DEFAULT_MAXBURSTLENGTH; + + conn->diskIoPending = 0; + conn->flagDelayedFree = 0; + + conn->portal.label = xstrdup(portal->label); + conn->portal.host = xstrdup(portal->host); + conn->portal.port = xstrdup(portal->port); + conn->portal.idx = portal->idx; + conn->portal.tag = portal->tag; + conn->portal.sock = -1; + conn->sock = sock; + conn->wsock = -1; + conn->kq = -1; + + conn->sess = NULL; + conn->params = NULL; + conn->state = CONN_STATE_INVALID; + conn->exec_logout = 0; + conn->max_pending = 0; + conn->queue_depth = 0; + conn->pending_r2t = 0; + conn->header_digest = 0; + conn->data_digest = 0; + conn->full_feature = 0; + conn->login_phase = ISCSI_LOGIN_PHASE_NONE; + conn->auth.user = NULL; + conn->auth.secret = NULL; + conn->auth.muser = NULL; + conn->auth.msecret = NULL; + conn->authenticated = 0; + conn->req_auth = 0; + conn->req_mutual = 0; + conn->inflight = 0; + conn->sender_waiting = 0; + istgt_queue_init(&conn->pending_pdus); + conn->r2t_tasks = xmalloc ((sizeof conn->r2t_tasks) + * (conn->max_r2t + 1)); + for (i = 0; i < (conn->max_r2t + 1); i++) { + conn->r2t_tasks[i] = NULL; + } + conn->task_pipe[0] = -1; + conn->task_pipe[1] = -1; + conn->max_task_queue = MAX_LU_QUEUE_DEPTH; + istgt_queue_init(&conn->task_queue); + istgt_queue_init(&conn->result_queue); + conn->exec_lu_task = NULL; + conn->running_tasks = 0; + + /*memset(conn->initiator_addr, 0, sizeof conn->initiator_addr); + memset(conn->target_addr, 0, sizeof conn->target_addr);*/ + + switch (sa->sa_family) { + case AF_INET6: + conn->initiator_family = AF_INET6; + rc = istgt_getaddr(sock, conn->target_addr, + sizeof conn->target_addr, + conn->initiator_addr, sizeof conn->initiator_addr, &conn->iaddr, &conn->iport); + if (rc < 0) { + ISTGT_ERRLOG("istgt_getaddr() failed\n"); + goto error_return; + } + break; + case AF_INET: + conn->initiator_family = AF_INET; + rc = istgt_getaddr(sock, conn->target_addr, + sizeof conn->target_addr, + conn->initiator_addr, sizeof conn->initiator_addr, &conn->iaddr, &conn->iport); + if (rc < 0) { + ISTGT_ERRLOG("istgt_getaddr() failed\n"); + goto error_return; + } + break; + default: + ISTGT_ERRLOG("unsupported family\n"); + goto error_return; + } + /*printf("sock=%d, addr=%s, peer=%s\n", + sock, conn->target_addr, + conn->initiator_addr);*/ + + /* wildcard? */ + if (strcasecmp(conn->portal.host, "[::]") == 0 + || strcasecmp(conn->portal.host, "[*]") == 0) { + if (conn->initiator_family != AF_INET6) { + ISTGT_ERRLOG("address family error\n"); + goto error_return; + } + snprintf(buf, sizeof buf, "[%s]", conn->target_addr); + xfree(conn->portal.host); + conn->portal.host = xstrdup(buf); + } else if (strcasecmp(conn->portal.host, "0.0.0.0") == 0 + || strcasecmp(conn->portal.host, "*") == 0) { + if (conn->initiator_family != AF_INET) { + ISTGT_ERRLOG("address family error\n"); + goto error_return; + } + snprintf(buf, sizeof buf, "%s", conn->target_addr); + xfree(conn->portal.host); + conn->portal.host = xstrdup(buf); + } + + /*memset(conn->initiator_name, 0, sizeof conn->initiator_name); + memset(conn->target_name, 0, sizeof conn->target_name); + memset(conn->initiator_port, 0, sizeof conn->initiator_port); + memset(conn->target_port, 0, sizeof conn->target_port);*/ + + /* set timeout msec. */ + rc = istgt_set_recvtimeout(conn->sock, conn->timeout * 1000); + if (rc != 0) { + ISTGT_ERRLOG("istgt_set_recvtimeo() failed\n"); + goto error_return; + } + rc = istgt_set_sendtimeout(conn->sock, conn->timeout * 1000); + if (rc != 0) { + ISTGT_ERRLOG("istgt_set_sendtimeo() failed\n"); + goto error_return; + } +#if defined (ISTGT_USE_IOVEC) + /* set low water mark */ + rc = istgt_set_recvlowat(conn->sock, ISCSI_BHS_LEN); + if (rc != 0) { + ISTGT_ERRLOG("istgt_set_recvlowat() failed\n"); + goto error_return; + } +#endif + + rc = pipe(conn->task_pipe); + if (rc != 0) { + ISTGT_ERRLOG("pipe() failed\n"); + conn->task_pipe[0] = -1; + conn->task_pipe[1] = -1; + goto error_return; + } + rc = pthread_mutex_init(&conn->diskioflag_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_mutex_init(&conn->task_queue_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_mutex_init(&conn->result_queue_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_cond_init(&conn->result_queue_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + goto error_return; + } + rc = pthread_mutex_init(&conn->wpdu_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_cond_init(&conn->wpdu_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + goto error_return; + } + rc = pthread_mutex_init(&conn->r2t_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_mutex_init(&conn->sender_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + rc = pthread_cond_init(&conn->sender_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + goto error_return; + } + + /* set default params */ + rc = istgt_iscsi_conn_params_init(&conn->params); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_conn_params_init() failed\n"); + goto error_return; + } + /* replace with config value */ + rc = istgt_iscsi_param_set_int(conn->params, + "MaxRecvDataSegmentLength", + conn->MaxRecvDataSegmentLength); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + + if (conn->MaxRecvDataSegmentLength < 8192) { + conn->recvbufsize = 8192; + conn->sendbufsize = 8192; + } else { + conn->recvbufsize = conn->MaxRecvDataSegmentLength; + conn->sendbufsize = conn->MaxRecvDataSegmentLength; + } + conn->recvbuf = xmalloc(conn->recvbufsize); + conn->sendbuf = xmalloc(conn->sendbufsize); + + conn->worksize = 0; + conn->workbuf = NULL; + + conn->StatSN = 0; + conn->isid = 0; + conn->tsih = 0; + + /* register global */ + rc = -1; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i < g_nconns; i++) { + if (g_conns[i] == NULL) { + g_conns[i] = conn; + conn->id = i; + if(i > g_max_connidx) + g_max_connidx++; + rc = 0; + break; + } + } + MTX_UNLOCK(&g_conns_mutex); + if (rc < 0) { + ISTGT_ERRLOG("no free conn slot available\n"); + error_return: + if (conn->task_pipe[0] != -1) + close(conn->task_pipe[0]); + if (conn->task_pipe[1] != -1) + close(conn->task_pipe[1]); + istgt_iscsi_param_free(conn->params); + istgt_queue_destroy(&conn->pending_pdus); + istgt_queue_destroy(&conn->task_queue); + istgt_queue_destroy(&conn->result_queue); + xfree(conn->portal.label); + xfree(conn->portal.host); + xfree(conn->portal.port); + xfree(conn->recvbuf); + xfree(conn->sendbuf); + xfree(conn); + return -1; + } + + /* create new thread */ + rc = pthread_create(&conn->thread, &istgt->attr, &worker, (void *)conn); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed\n"); + goto error_return; + } + snprintf(conn->thr, sizeof conn->thr, "c#%d.%ld.%d", conn->id, (uint64_t)(((uint64_t *)(conn->thread))[0]), ntohs(conn->iport)); + rc = pthread_detach(conn->thread); + if (rc != 0) { + ISTGT_ERRLOG("pthread_detach() failed\n"); + goto error_return; + } + return 0; +} + +int +istgt_create_sess(ISTGT_Ptr istgt, CONN_Ptr conn, ISTGT_LU_Ptr lu) +{ + SESS_Ptr sess; + int rc; + + sess = xmalloc(sizeof *sess); + memset(sess, 0, sizeof *sess); + + /* configuration values */ + MTX_LOCK(&istgt->mutex); + if (lu != NULL) { + MTX_LOCK(&lu->mutex); + } + sess->MaxConnections = istgt->MaxConnections; + if (lu != NULL) { + sess->MaxOutstandingR2T = lu->MaxOutstandingR2T; + } else { + sess->MaxOutstandingR2T = istgt->MaxOutstandingR2T; + } +#if 0 + if (sess->MaxOutstandingR2T > conn->max_r2t) { + if (conn->max_r2t > 0) { + sess->MaxOutstandingR2T = conn->max_r2t; + } else { + sess->MaxOutstandingR2T = 1; + } + } +#else + if (sess->MaxOutstandingR2T < 1) { + sess->MaxOutstandingR2T = 1; + } + /* limit up to MaxOutstandingR2T */ + if (sess->MaxOutstandingR2T < conn->max_r2t) { + conn->max_r2t = sess->MaxOutstandingR2T; + } +#endif + if (lu != NULL) { + sess->DefaultTime2Wait = lu->DefaultTime2Wait; + sess->DefaultTime2Retain = lu->DefaultTime2Retain; + sess->FirstBurstLength = lu->FirstBurstLength; + sess->MaxBurstLength = lu->MaxBurstLength; + conn->MaxRecvDataSegmentLength + = lu->MaxRecvDataSegmentLength; + sess->InitialR2T = lu->InitialR2T; + sess->ImmediateData = lu->ImmediateData; + sess->DataPDUInOrder = lu->DataPDUInOrder; + sess->DataSequenceInOrder = lu->DataSequenceInOrder; + sess->ErrorRecoveryLevel = lu->ErrorRecoveryLevel; + } else { + sess->DefaultTime2Wait = istgt->DefaultTime2Wait; + sess->DefaultTime2Retain = istgt->DefaultTime2Retain; + sess->FirstBurstLength = istgt->FirstBurstLength; + sess->MaxBurstLength = istgt->MaxBurstLength; + conn->MaxRecvDataSegmentLength + = istgt->MaxRecvDataSegmentLength; + sess->InitialR2T = istgt->InitialR2T; + sess->ImmediateData = istgt->ImmediateData; + sess->DataPDUInOrder = istgt->DataPDUInOrder; + sess->DataSequenceInOrder = istgt->DataSequenceInOrder; + sess->ErrorRecoveryLevel = istgt->ErrorRecoveryLevel; + } + if (lu != NULL) { + MTX_UNLOCK(&lu->mutex); + } + MTX_UNLOCK(&istgt->mutex); + + sess->initiator_port = xstrdup(conn->initiator_port); + sess->target_name = xstrdup(conn->target_name); + sess->tag = conn->portal.tag; + + sess->max_conns = sess->MaxConnections; + sess->conns = xmalloc(sizeof *sess->conns * sess->max_conns); + memset(sess->conns, 0, sizeof *sess->conns * sess->max_conns); + sess->connections = 0; + + sess->conns[sess->connections] = conn; + sess->connections++; + + sess->req_mcs_cond = 0; + sess->params = NULL; + sess->lu = NULL; + sess->isid = 0; + sess->tsih = 0; + + sess->initial_r2t = 0; + sess->immediate_data = 0; + + rc = pthread_mutex_init(&sess->mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + error_return: + istgt_iscsi_param_free(sess->params); + xfree(sess->initiator_port); + xfree(sess->target_name); + xfree(sess->conns); + xfree(sess); + conn->sess = NULL; + return -1; + } + rc = pthread_cond_init(&sess->mcs_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + goto error_return; + } + + /* set default params */ + rc = istgt_iscsi_sess_params_init(&sess->params); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_sess_params_init() failed\n"); + goto error_return; + } + /* replace with config value */ + rc = istgt_iscsi_param_set_int(sess->params, + "MaxConnections", + sess->MaxConnections); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "MaxOutstandingR2T", + sess->MaxOutstandingR2T); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "DefaultTime2Wait", + sess->DefaultTime2Wait); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "DefaultTime2Retain", + sess->DefaultTime2Retain); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "FirstBurstLength", + sess->FirstBurstLength); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "MaxBurstLength", + sess->MaxBurstLength); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set(sess->params, + "InitialR2T", + sess->InitialR2T ? "Yes" : "No"); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set(sess->params, + "ImmediateData", + sess->ImmediateData ? "Yes" : "No"); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set(sess->params, + "DataPDUInOrder", + sess->DataPDUInOrder ? "Yes" : "No"); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set(sess->params, + "DataSequenceInOrder", + sess->DataSequenceInOrder ? "Yes" : "No"); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set() failed\n"); + goto error_return; + } + rc = istgt_iscsi_param_set_int(sess->params, + "ErrorRecoveryLevel", + sess->ErrorRecoveryLevel); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + + /* realloc buffer */ + rc = istgt_iscsi_param_set_int(conn->params, + "MaxRecvDataSegmentLength", + conn->MaxRecvDataSegmentLength); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_set_int() failed\n"); + goto error_return; + } + if (conn->MaxRecvDataSegmentLength != conn->recvbufsize) { + xfree(conn->recvbuf); + xfree(conn->sendbuf); + if (conn->MaxRecvDataSegmentLength < 8192) { + conn->recvbufsize = 8192; + conn->sendbufsize = 8192; + } else { + conn->recvbufsize = conn->MaxRecvDataSegmentLength; + conn->sendbufsize = conn->MaxRecvDataSegmentLength; + } + conn->recvbuf = xmalloc(conn->recvbufsize); + conn->sendbuf = xmalloc(conn->sendbufsize); + } + + /* sess for first connection of session */ + conn->sess = sess; + return 0; +} + +static int +istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid) +{ + SESS_Ptr sess; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "append session: isid=%"PRIx64", tsih=%u, cid=%u\n", + isid, tsih, cid); + + sess = NULL; + rc = -1; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + if (g_conns[i] == NULL || g_conns[i]->sess == NULL) + continue; + sess = g_conns[i]->sess; + MTX_LOCK(&sess->mutex); + if (conn->portal.tag == sess->tag + && strcasecmp(conn->initiator_port, sess->initiator_port) == 0 + && strcasecmp(conn->target_name, sess->target_name) == 0 + && (isid == sess->isid && tsih == sess->tsih)) { + /* match tag and initiator port and target */ + rc = 0; + break; + } + MTX_UNLOCK(&sess->mutex); + } + if (rc < 0) { + /* no match */ + MTX_UNLOCK(&g_conns_mutex); + ISTGT_ERRLOG("no MCS session for isid=%"PRIx64", tsih=%d, cid=%d\n", + isid, tsih, cid); + return -1; + } + /* sess is LOCK by loop */ + if (sess->connections >= sess->max_conns + || sess->connections >= sess->MaxConnections) { + /* no slot for connection */ + MTX_UNLOCK(&sess->mutex); + MTX_UNLOCK(&g_conns_mutex); + ISTGT_ERRLOG("too many connections for isid=%"PRIx64 + ", tsih=%d, cid=%d\n", + isid, tsih, cid); + return -1; + } + printf("Connections(tsih %d): %d\n", sess->tsih, sess->connections); + conn->sess = sess; + sess->conns[sess->connections] = conn; + sess->connections++; + MTX_UNLOCK(&sess->mutex); + MTX_UNLOCK(&g_conns_mutex); + + return 0; +} + +static void +istgt_free_sess(SESS_Ptr sess) +{ + if (sess == NULL) + return; + (void) pthread_mutex_destroy(&sess->mutex); + (void) pthread_cond_destroy(&sess->mcs_cond); + istgt_iscsi_param_free(sess->params); + xfree(sess->initiator_port); + xfree(sess->target_name); + xfree(sess->conns); + xfree(sess); +} + +void +istgt_close_conn(CONN_Ptr conn) +{ + if (conn == NULL) + return; + if (conn->task_pipe[0] != -1) + close(conn->task_pipe[0]); + if (conn->task_pipe[1] != -1) + close(conn->task_pipe[1]); + conn->task_pipe[0] = -1; + conn->task_pipe[1] = -1; + conn->closetime = time(NULL); +} + +void +istgt_free_conn(CONN_Ptr conn) +{ +/* + if (conn == NULL) + return; + if (conn->task_pipe[0] != -1) + close(conn->task_pipe[0]); + if (conn->task_pipe[1] != -1) + close(conn->task_pipe[1]); +*/ + (void) pthread_mutex_destroy(&conn->task_queue_mutex); + (void) pthread_mutex_destroy(&conn->result_queue_mutex); + (void) pthread_mutex_destroy(&conn->diskioflag_mutex); + (void) pthread_cond_destroy(&conn->result_queue_cond); + (void) pthread_mutex_destroy(&conn->wpdu_mutex); + (void) pthread_cond_destroy(&conn->wpdu_cond); + (void) pthread_mutex_destroy(&conn->r2t_mutex); + (void) pthread_mutex_destroy(&conn->sender_mutex); + (void) pthread_cond_destroy(&conn->sender_cond); + istgt_iscsi_param_free(conn->params); + istgt_queue_destroy(&conn->pending_pdus); + istgt_queue_destroy(&conn->task_queue); + istgt_queue_destroy(&conn->result_queue); + xfree(conn->r2t_tasks); + xfree(conn->portal.label); + xfree(conn->portal.host); + xfree(conn->portal.port); + xfree(conn->auth.user); + xfree(conn->auth.secret); + xfree(conn->auth.muser); + xfree(conn->auth.msecret); + xfree(conn->recvbuf); + xfree(conn->sendbuf); + xfree(conn->workbuf); + xfree(conn); +} + +ISTGT_QUEUE closedconns; + +static void +istgt_remove_conn(CONN_Ptr conn) +{ + SESS_Ptr sess; + int clear = 0; + ISTGT_LU_DISK *spec = NULL; + + if(conn->sess != NULL){ + if(conn->sess->lu != NULL) { + MTX_LOCK(&conn->sess->lu->mutex); + conn->sess->lu->conns--; + MTX_UNLOCK(&conn->sess->lu->mutex); + clear = 1; + spec = (ISTGT_LU_DISK *)conn->sess->lu->lun[0].spec; + } + } + int idx; + int i, j; + int delayedFree = 0; + int sessConns = 0, ioPending = 0; + int rc = 0; + + idx = -1; + sess = conn->sess; + conn->sess = NULL; + if (sess == NULL) { + istgt_close_conn(conn); + istgt_free_conn(conn); + return; + } + + MTX_LOCK(&sess->mutex); + for (i = 0; i < sess->connections; i++) { + if (sess->conns[i] == conn) { + idx = i; + break; + } + } + if (sess->connections < 1) { + ISTGT_ERRLOG("zero connection\n"); + sess->connections = 0; + } else { + if (idx < 0) { + ISTGT_ERRLOG("remove conn not found\n"); + } else { + for (j = idx; j < sess->connections - 1; j++) { + sess->conns[j] = sess->conns[j + 1]; + } + sess->conns[sess->connections - 1] = NULL; + sess->connections--; + } + } + sessConns = sess->connections; + MTX_UNLOCK(&sess->mutex); + if (sessConns == 0) { + if(clear == 1) { + MTX_LOCK(&spec->pr_rsv_mutex); + if(spec->spc2_reserved == 1 && clear_resv == 1) { + if(strcmp(conn->initiator_port, spec->rsv_port) == 0) { + /* release reservation by key */ + ISTGT_LOG("Clearing spc2 Reservations"); + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->spc2_reserved = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + /* remove registrations */ + for (i = 0; i < spec->npr_keys; i++) { + if(spec->pr_keys[i].registered_initiator_port == conn->initiator_port) { + istgt_lu_disk_free_pr_key(&spec->pr_keys[i]); + memset(&spec->pr_keys[i], 0, sizeof(spec->pr_keys[i])); + } + } + } + } + MTX_UNLOCK(&spec->pr_rsv_mutex); + } + /* cleanup last connection */ + istgt_lu_free_tsih(sess->lu, sess->tsih, conn->initiator_port); + rc = istgt_lu_remove_nexus(sess->lu, conn->initiator_port); + if (rc < 0) { + /* Ignore Error */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Failed to remove the Nexus\n"); + } + istgt_free_sess(sess); + } + MTX_LOCK(&conn->diskioflag_mutex); + ioPending = conn->diskIoPending; + if(conn->diskIoPending != 0) { + conn->flagDelayedFree = 1; + delayedFree = 1; + } else { + conn->flagDelayedFree = 0; + } + MTX_UNLOCK(&conn->diskioflag_mutex); + + ISTGT_NOTICELOG("remove_conn->initiator:%s(%s) Target: %s(%s LU%d) conn:%p:%d tsih:%d connections:%d %s IOPending=%d", + conn->initiator_addr, conn->initiator_name, conn->target_addr, conn->target_name, + (sess->lu==NULL)?0:sess->lu->num, conn, conn->cid, sess->tsih, sessConns, + (delayedFree == 1) ? "delay_free" : "", ioPending); + if (strcmp(conn->target_name, "dummy") && conn->exec_logout == 0) + ioctl_call(conn, TYPE_CONNBRK); +/* + if (delayedFree == 0) + istgt_free_conn(conn); +*/ + istgt_close_conn(conn); + istgt_queue_enqueue(&closedconns, conn); +} + +static int +istgt_iscsi_drop_all_conns(CONN_Ptr conn) +{ + CONN_Ptr xconn; + int max_conns; + int num; + int rc; + int i; + + MTX_LOCK(&conn->istgt->mutex); + max_conns = conn->istgt->MaxConnections; + MTX_UNLOCK(&conn->istgt->mutex); + num = 0; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + xconn = g_conns[i]; + if (xconn == NULL) + continue; + if (strcasecmp(conn->initiator_name, xconn->initiator_name) != 0) { + continue; + } + if (strcasecmp(conn->target_name, xconn->target_name) == 0) { + if (xconn->sess != NULL) { + printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n", + xconn->initiator_name, + xconn->initiator_addr, + xconn->sess->tsih, xconn->cid); + } else { + printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n", + xconn->initiator_name, + xconn->initiator_addr, + xconn->cid); + } + xconn->state = CONN_STATE_EXITING; + num++; + } + } + if(num!=0){ + istgt_yield(); + sleep(1); + ISTGT_NOTICELOG("drop all %d connections %d %s by %s\n", + num, conn->id, conn->target_name, conn->initiator_name); + } + if (num > max_conns + 1) { + for (i = 0; i <= g_max_connidx; i++) { + xconn = g_conns[i]; + if (xconn == NULL) + continue; + if (xconn == conn) + continue; + if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) { + continue; + } + if (strcasecmp(conn->target_name, xconn->target_name) == 0) { + if (xconn->sess != NULL) { + printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->sess->tsih, xconn->cid); + } else { + printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->cid); + } + rc = pthread_cancel(xconn->thread); + if (rc != 0) { + ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc); + } + } + } + } + MTX_UNLOCK(&g_conns_mutex); + return 0; +} + +static int +istgt_iscsi_drop_old_conns(CONN_Ptr conn) +{ + CONN_Ptr xconn; + int max_conns; + int num; + int rc; + int i; + + MTX_LOCK(&conn->istgt->mutex); + max_conns = conn->istgt->MaxConnections; + MTX_UNLOCK(&conn->istgt->mutex); + num = 0; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + xconn = g_conns[i]; + if (xconn == NULL) + continue; + if (xconn == conn) + continue; + if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) { + continue; + } + if (strcasecmp(conn->target_name, xconn->target_name) == 0) { + if (xconn->sess != NULL) { + printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->sess->tsih, xconn->cid); + } else { + printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->cid); + } + xconn->state = CONN_STATE_EXITING; + num++; + } + } + if(num!=0){ + istgt_yield(); + sleep(1); + ISTGT_NOTICELOG("drop all %d old connections %d %s by %s\n", + num, conn->id, conn->target_name, conn->initiator_port); + } + if (num > max_conns + 1) { + for (i = 0; i <= g_max_connidx; i++) { + xconn = g_conns[i]; + if (xconn == NULL) + continue; + if (xconn == conn) + continue; + if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) { + continue; + } + if (strcasecmp(conn->target_name, xconn->target_name) == 0) { + if (xconn->sess != NULL) { + printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->sess->tsih, xconn->cid); + } else { + printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n", + xconn->initiator_port, + xconn->initiator_addr, + xconn->cid); + } + rc = pthread_cancel(xconn->thread); + if (rc != 0) { + ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc); + } + } + } + } + MTX_UNLOCK(&g_conns_mutex); + return 0; +} + +#ifdef __linux__ +static void ioctl_call(CONN_Ptr conn __attribute__((__unused__)), enum iscsi_log log_type __attribute__((__unused__))) {} +#else +static void ioctl_call(CONN_Ptr conn, enum iscsi_log log_type) +{ + int fd; + char ebuf[2048]; + char info[16]; + struct istgt_detail* idetail; + + switch (log_type) { + case TYPE_LOGIN: + snprintf(info, sizeof info, "login"); + break; + case TYPE_LOGOUT: + snprintf(info, sizeof info, "logout"); + break; + case TYPE_CONNBRK: + snprintf(info, sizeof info, "logout_connbrk"); + break; + default: + snprintf(info, sizeof info, "invalid"); + break; + } + + // Send ioctl to kernel for logging purpose + fd = open(ISCSI_SOCKET, O_WRONLY); + if (fd == -1) { + snprintf(ebuf, sizeof ebuf, + "fd opening failed: %s %s %s %s %s %s %s %s %s errno= %d", + info, "Initiator IP:", + conn->initiator_addr, "Name:", conn->initiator_name, "Target IP:", + conn->target_addr, "Name:", conn->target_name, errno); + ISTGT_NOTICELOG("%s", ebuf); + return; + } + + idetail = (struct istgt_detail *)malloc(sizeof (*idetail)); + if (idetail == (struct istgt_detail *)NULL) { + snprintf(ebuf, sizeof ebuf, + "out of memory: %s %s %s %s %s %s %s %s %s errno= %d", + info, "Initiator IP:", + conn->initiator_addr, "Name:", conn->initiator_name, "Target IP:", + conn->target_addr, "Name:", conn->target_name, errno); + ISTGT_NOTICELOG("%s", ebuf); + close(fd); + return; + } + idetail->login_status = log_type; + strncpy(idetail->initiator_addr, conn->initiator_addr, 64); + strncpy(idetail->target_addr, conn->target_addr, 64); + strncpy(idetail->initiator_name, conn->initiator_name, 256); + strncpy(idetail->target_name, conn->target_name, 256); + if (ioctl(fd, DIO_ISCSIWR, idetail) == -1) { + snprintf(ebuf, sizeof ebuf, + "ioctl failed: %s %s %s %s %s %s %s %s %s errno= %d", + info, "Initiator IP:", + conn->initiator_addr, "Name:", conn->initiator_name, "Target IP:", + conn->target_addr, "Name:", conn->target_name, errno); + ISTGT_NOTICELOG("%s", ebuf); + } + free(idetail); + close(fd); +} +#endif + +void +istgt_lock_gconns(void) +{ + MTX_LOCK(&g_conns_mutex); +} + +void +istgt_unlock_gconns(void) +{ + MTX_UNLOCK(&g_conns_mutex); +} + +int +istgt_get_gnconns(void) +{ + return g_nconns; +} + +CONN_Ptr +istgt_get_gconn(int idx) +{ + if (idx >= g_nconns) + return NULL; + return g_conns[idx]; +} + +int +istgt_get_active_conns(void) +{ + CONN_Ptr conn; + int num = 0; + int i; + + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + conn = g_conns[i]; + if (conn == NULL) + continue; + num++; + } + MTX_UNLOCK(&g_conns_mutex); + return num; +} + +int +istgt_stop_conns(void) +{ + CONN_Ptr conn; + char tmp[1]; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_stop_conns\n"); + tmp[0] = 'E'; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + conn = g_conns[i]; + if (conn == NULL) + continue; + rc = write(conn->task_pipe[1], tmp, 1); + if(rc < 0 || rc != 1) { + ISTGT_ERRLOG("write() failed\n"); + /* ignore error */ + } + } + MTX_UNLOCK(&g_conns_mutex); + return 0; +} + +CONN_Ptr +istgt_find_conn(const char *initiator_port, const char *target_name, uint16_t tsih) +{ + CONN_Ptr conn; + SESS_Ptr sess; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "initiator_port=%s, target=%s, TSIH=%u", + initiator_port, target_name, tsih); + sess = NULL; + rc = -1; + //MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + conn = g_conns[i]; + if (conn == NULL || conn->sess == NULL) + continue; + sess = conn->sess; + MTX_LOCK(&sess->mutex); + if (strcasecmp(initiator_port, sess->initiator_port) == 0 + && strcasecmp(target_name, sess->target_name) == 0 + && (tsih == sess->tsih)) { + /* match initiator port and target */ + rc = 0; + break; + } + MTX_UNLOCK(&sess->mutex); + } + if (rc < 0) { + //MTX_UNLOCK(&g_conns_mutex); + return NULL; + } + MTX_UNLOCK(&sess->mutex); + //MTX_UNLOCK(&g_conns_mutex); + return conn; +} + +int +istgt_iscsi_init(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + int rc; + int allocsize; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_init\n"); + sp = istgt_find_cf_section(istgt->config, "Global"); + if (sp == NULL) { + ISTGT_ERRLOG("find_cf_section failed()\n"); + return -1; + } + + rc = pthread_mutex_init(&g_conns_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + rc = pthread_mutex_init(&g_last_tsih_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + g_max_connidx = -1; + g_nconns = MAX_LOGICAL_UNIT * istgt->MaxSessions * istgt->MaxConnections; + g_nconns += MAX_LOGICAL_UNIT * istgt->MaxConnections; + //g_conns = xmalloc(sizeof *g_conns * g_nconns); + allocsize = ((sizeof (CONN_Ptr *)) * (g_nconns + 100)); + g_conns = xmalloc(allocsize); + bzero(g_conns, allocsize); + g_last_tsih = 0; + + return 0; +} + +int +istgt_iscsi_shutdown(ISTGT_Ptr istgt __attribute__((__unused__))) +{ + CONN_Ptr conn; + int retry = 10; + int num; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_shutdown\n"); + + num = 0; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + conn = g_conns[i]; + if (conn == NULL) + continue; + conn->state = CONN_STATE_EXITING; + num++; + } + MTX_UNLOCK(&g_conns_mutex); + + if (num != 0) { + /* check threads */ + while (retry > 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "check thread retry=%d\n", + retry); + sleep(1); + num = 0; + MTX_LOCK(&g_conns_mutex); + for (i = 0; i <= g_max_connidx; i++) { + conn = g_conns[i]; + if (conn == NULL) + continue; + num++; + } + MTX_UNLOCK(&g_conns_mutex); + if (num == 0) + break; + retry--; + } + } + + rc = pthread_mutex_destroy(&g_last_tsih_mutex); + if (rc != 0) { + ISTGT_ERRLOG("mutex_destroy() failed\n"); + return -1; + } + rc = pthread_mutex_destroy(&g_conns_mutex); + if (rc != 0) { + ISTGT_ERRLOG("mutex_destroy() failed\n"); + return -1; + } + + if (num == 0) { + xfree(g_conns); + g_conns = NULL; + } + + return 0; +} diff --git a/src/istgt_iscsi.h b/src/istgt_iscsi.h new file mode 100644 index 00000000..3891b429 --- /dev/null +++ b/src/istgt_iscsi.h @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_ISCSI_H +#define ISTGT_ISCSI_H + +#include +#include +#include "istgt.h" +#include "istgt_iscsi_param.h" +#include "istgt_lu.h" +#include "istgt_queue.h" +#include +#define ISCSI_BHS_LEN 48 +#define ISCSI_ALIGNMENT 4 +/* support version - RFC3720(10.12.4) */ +#define ISCSI_VERSION 0x00 + +#define ISCSI_ALIGN(SIZE) \ + (((SIZE) + (ISCSI_ALIGNMENT - 1)) & ~(ISCSI_ALIGNMENT - 1)) + +#define ISCSI_TEXT_MAX_KEY_LEN 64 +/* for authentication key (non encoded 1024bytes) RFC3720(5.1/11.1.4) */ +#define ISCSI_TEXT_MAX_VAL_LEN 8192 + +#define SESS_MTX_LOCK(CONN) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_mutex_lock(&(CONN)->sess->mutex)) != 0) { \ + ISTGT_ERRLOG("sess lock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) +#define SESS_MTX_UNLOCK(CONN) \ + do { \ + int _rc_; \ + if ((_rc_ = pthread_mutex_unlock(&(CONN)->sess->mutex)) != 0) { \ + ISTGT_ERRLOG("sess unlock error:%d", _rc_); \ + pthread_exit(NULL); \ + } \ + } while (0) + +typedef enum { + /* Initiator opcodes */ + ISCSI_OP_NOPOUT = 0x00, + ISCSI_OP_SCSI = 0x01, + ISCSI_OP_TASK = 0x02, + ISCSI_OP_LOGIN = 0x03, + ISCSI_OP_TEXT = 0x04, + ISCSI_OP_SCSI_DATAOUT = 0x05, + ISCSI_OP_LOGOUT = 0x06, + ISCSI_OP_SNACK = 0x10, + ISCSI_OP_VENDOR_1C = 0x1c, + ISCSI_OP_VENDOR_1D = 0x1d, + ISCSI_OP_VENDOR_1E = 0x1e, + + /* Target opcodes */ + ISCSI_OP_NOPIN = 0x20, + ISCSI_OP_SCSI_RSP = 0x21, + ISCSI_OP_TASK_RSP = 0x22, + ISCSI_OP_LOGIN_RSP = 0x23, + ISCSI_OP_TEXT_RSP = 0x24, + ISCSI_OP_SCSI_DATAIN = 0x25, + ISCSI_OP_LOGOUT_RSP = 0x26, + ISCSI_OP_R2T = 0x31, + ISCSI_OP_ASYNC = 0x32, + ISCSI_OP_VENDOR_3C = 0x3c, + ISCSI_OP_VENDOR_3D = 0x3d, + ISCSI_OP_VENDOR_3E = 0x3e, + ISCSI_OP_REJECT = 0x3f, +} ISCSI_OP; + +typedef enum { + ISCSI_TASK_FUNC_ABORT_TASK = 1, + ISCSI_TASK_FUNC_ABORT_TASK_SET = 2, + ISCSI_TASK_FUNC_CLEAR_ACA = 3, + ISCSI_TASK_FUNC_CLEAR_TASK_SET = 4, + ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET = 5, + ISCSI_TASK_FUNC_TARGET_WARM_RESET = 6, + ISCSI_TASK_FUNC_TARGET_COLD_RESET = 7, + ISCSI_TASK_FUNC_TASK_REASSIGN = 8, +} ISCSI_TASK_FUNC; + + +typedef struct iscsi_bhs_t { + /* 0-3 */ + uint8_t opcode; + uint8_t opcode_specific1[3]; + /* 4-7 */ + uint8_t total_ahs_len; + uint8_t data_segment_len[3]; + /* 8-11 */ + union { + uint8_t lun1[4]; + uint8_t opcode_specific2[4]; + } u1; + /* 12-15 */ + union { + uint8_t lun2[4]; + uint8_t opcode_specific3[4]; + } u2; + /* 16-19 */ + uint8_t inititator_task_tag[4]; + /* 20-47 */ + uint8_t opcode_specific4[28]; +} ISCSI_BHS; + +typedef struct iscsi_ahs_t { + /* 0-3 */ + uint8_t ahs_len[2]; + uint8_t ahs_type; + uint8_t ahs_specific1; + /* 4-x */ + uint8_t ahs_specific2[]; +} ISCSI_AHS; + +#define ISCSI_DIGEST_LEN 4 +typedef struct iscsi_pdu_t { + ISCSI_BHS bhs; + ISCSI_AHS *ahs; + union { + uint8_t header_digest[ISCSI_DIGEST_LEN]; + uint64_t header_digestX; + }; + uint8_t *data; + union { + uint8_t data_digest[ISCSI_DIGEST_LEN]; + uint64_t data_digestX; + }; + size_t total_ahs_len; + size_t data_segment_len; + uint8_t opcode; + uint8_t scsi_op; + uint16_t dummy; + struct timespec start0; + struct timespec start; +} ISCSI_PDU; +typedef ISCSI_PDU *ISCSI_PDU_Ptr; + +typedef enum { + CONN_STATE_INVALID = 0, + CONN_STATE_RUNNING = 1, + CONN_STATE_EXITING = 2, + CONN_STATE_SHUTDOWN = 3, +} CONN_STATE; + +typedef enum { + ISCSI_LOGIN_PHASE_NONE = 0, + ISCSI_LOGIN_PHASE_START = 1, + ISCSI_LOGIN_PHASE_SECURITY = 2, + ISCSI_LOGIN_PHASE_OPERATIONAL = 3, + ISCSI_LOGIN_PHASE_FULLFEATURE = 4, +} ISCSI_LOGIN_PHASE; + +typedef enum { + ISTGT_CHAP_PHASE_NONE = 0, + ISTGT_CHAP_PHASE_WAIT_A = 1, + ISTGT_CHAP_PHASE_WAIT_NR = 2, + ISTGT_CHAP_PHASE_END = 3, +} ISTGT_CHAP_PHASE; + +#define ISTGT_CHAP_CHALLENGE_LEN 1024 +typedef struct istgt_chap_auth_t { + ISTGT_CHAP_PHASE chap_phase; + + char *user; + char *secret; + char *muser; + char *msecret; + + uint8_t chap_id[1]; + uint8_t chap_mid[1]; + int chap_challenge_len; + uint8_t chap_challenge[ISTGT_CHAP_CHALLENGE_LEN]; + int chap_mchallenge_len; + uint8_t chap_mchallenge[ISTGT_CHAP_CHALLENGE_LEN]; +} ISTGT_CHAP_AUTH; + +typedef struct istgt_r2t_task_t { + struct istgt_conn_t *conn; + ISTGT_LU_Ptr lu; + uint64_t lun; + uint32_t CmdSN; + uint32_t task_tag; + uint32_t transfer_len; + uint32_t transfer_tag; + + uint64_t iobufsize; + int iobufindx; + struct iovec iobuf[20]; + //int iobufoff[20]; int iobufsize[20]; uint8_t *iobuf[20]; + + uint32_t R2TSN; + uint32_t DataSN; + int F_bit; + int offset; +} ISTGT_R2T_TASK; +typedef ISTGT_R2T_TASK *ISTGT_R2T_TASK_Ptr; + +typedef struct istgt_conn_t { + int id; + + ISTGT_Ptr istgt; + PORTAL portal; + int sock; + int wsock; +#ifdef ISTGT_USE_KQUEUE + int kq; +#endif /* ISTGT_USE_KQUEUE */ + char thr[20]; + char sthr[20]; + pthread_t thread; + pthread_t sender_thread; + pthread_mutex_t sender_mutex; + pthread_cond_t sender_cond; + struct istgt_sess_t *sess; + + CONN_STATE state; + int exec_logout; + + int max_pending; + int queue_depth; + pthread_mutex_t wpdu_mutex; + pthread_cond_t wpdu_cond; + ISTGT_QUEUE pending_pdus; + ISCSI_PDU pdu; + + int max_r2t; + int pending_r2t; + pthread_mutex_t r2t_mutex; + ISTGT_R2T_TASK_Ptr *r2t_tasks; + + int task_pipe[2]; + int max_task_queue; + pthread_mutex_t task_queue_mutex; + ISTGT_QUEUE task_queue; + pthread_mutex_t result_queue_mutex; + pthread_cond_t result_queue_cond; + ISTGT_QUEUE result_queue; + ISTGT_LU_TASK_Ptr exec_lu_task; + int running_tasks; + + uint16_t cid; + uint16_t iport; + uint32_t iaddr; + /* IP address */ + int initiator_family; + char initiator_addr[MAX_INITIATOR_ADDR]; + char target_addr[MAX_TARGET_ADDR]; + + int diskIoPending; + int flagDelayedFree; + pthread_mutex_t diskioflag_mutex; + + /* Initiator/Target port binds */ + char initiator_name[MAX_INITIATOR_NAME]; + char target_name[MAX_TARGET_NAME]; + char initiator_port[MAX_INITIATOR_NAME]; + char target_port[MAX_TARGET_NAME]; + uint8_t inn_len; + uint8_t inp_len; + uint8_t tn_len; + uint8_t tp_len; + /* for fast access */ + int header_digest; + int data_digest; + int full_feature; + + ISCSI_PARAM *params; + ISCSI_LOGIN_PHASE login_phase; + ISTGT_CHAP_AUTH auth; + int authenticated; + int req_auth; + int req_mutual; + + int timeout; + int nopininterval; + + int TargetMaxRecvDataSegmentLength; + int MaxRecvDataSegmentLength; + int MaxOutstandingR2T; + int FirstBurstLength; + int MaxBurstLength; + + int recvbufsize; + int sendbufsize; + uint8_t *recvbuf; + uint8_t *sendbuf; + + int worksize; + uint8_t *workbuf; + + uint32_t StatSN; + + uint64_t isid; + uint16_t tsih; + + time_t closetime; + int inflight; + int sender_waiting; +} CONN; +typedef CONN *CONN_Ptr; + +typedef struct istgt_sess_t { + int connections; + int max_conns; + CONN_Ptr *conns; + + pthread_mutex_t mutex; + pthread_cond_t mcs_cond; + int req_mcs_cond; + + char *initiator_port; + char *target_name; + int tag; + + uint64_t isid; + uint16_t tsih; + ISTGT_LU_Ptr lu; + + ISCSI_PARAM *params; + + int MaxConnections; + int MaxOutstandingR2T; + int DefaultTime2Wait; + int DefaultTime2Retain; + int FirstBurstLength; + int MaxBurstLength; + int InitialR2T; + int ImmediateData; + int DataPDUInOrder; + int DataSequenceInOrder; + int ErrorRecoveryLevel; + + int initial_r2t; + int immediate_data; + + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t MaxCmdSN_local; +} SESS; +typedef SESS *SESS_Ptr; + +int istgt_iscsi_send_async(CONN_Ptr conn); +void istgt_free_conn(CONN_Ptr conn); +void istgt_close_conn(CONN_Ptr conn); +void istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey); + +#endif /* ISTGT_ISCSI_H */ diff --git a/src/istgt_iscsi_param.c b/src/istgt_iscsi_param.c new file mode 100644 index 00000000..6cd86030 --- /dev/null +++ b/src/istgt_iscsi_param.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "istgt.h" +#include "istgt_log.h" +#include "istgt_misc.h" +#include "istgt_iscsi.h" +#include "istgt_iscsi_param.h" + +void +istgt_iscsi_param_free(ISCSI_PARAM *params) +{ + ISCSI_PARAM *param, *next_param; + + if (params == NULL) + return; + for (param = params; param != NULL; param = next_param) { + next_param = param->next; + xfree(param->list); + xfree(param->val); + xfree(param->key); + xfree(param); + } +} + +ISCSI_PARAM * +istgt_iscsi_param_find(ISCSI_PARAM *params, const char *key) +{ + ISCSI_PARAM *param; + + if (params == NULL || key == NULL) + return NULL; + for (param = params; param != NULL; param = param->next) { + if (param->key != NULL && param->key[0] == key[0] + && strcasecmp(param->key, key) == 0) { + return param; + } + } + return NULL; +} + +int +istgt_iscsi_param_del(ISCSI_PARAM **params, const char *key) +{ + ISCSI_PARAM *param, *prev_param = NULL; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "del %s\n", key); + if (params == NULL || key == NULL) + return 0; + for (param = *params; param != NULL; param = param->next) { + if (param->key != NULL && param->key[0] == key[0] + && strcasecmp(param->key, key) == 0) { + if (prev_param != NULL) { + prev_param->next = param->next; + } else { + *params = param->next; + } + param->next = NULL; + istgt_iscsi_param_free(param); + return 0; + } + prev_param = param; + } + return -1; +} + +int +istgt_iscsi_param_add(ISCSI_PARAM **params, const char *key, const char *val, const char *list, int type) +{ + ISCSI_PARAM *param, *last_param; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add %s=%s, list=[%s], type=%d\n", + key, val, list, type); + if (key == NULL) + return -1; + param = istgt_iscsi_param_find(*params, key); + if (param != NULL) { + istgt_iscsi_param_del(params, key); + } + param = xmalloc(sizeof *param); + memset(param, 0, sizeof *param); + param->next = NULL; + param->key = xstrdup(key); + param->val = xstrdup(val); + param->list = xstrdup(list); + param->type = type; + + last_param = *params; + if (last_param != NULL) { + while (last_param->next != NULL) { + last_param = last_param->next; + } + last_param->next = param; + } else { + *params = param; + } + + return 0; +} + +int +istgt_iscsi_param_set(ISCSI_PARAM *params, const char *key, const char *val) +{ + ISCSI_PARAM *param; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set %s=%s\n", key, val); + param = istgt_iscsi_param_find(params, key); + if (param == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %s\n", key); + return -1; + } + + xfree(param->val); + param->val = xstrdup(val); + + return 0; +} + +int +istgt_iscsi_param_set_int(ISCSI_PARAM *params, const char *key, int val) +{ + char buf[MAX_TMPBUF]; + ISCSI_PARAM *param; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set %s=%d\n", key, val); + param = istgt_iscsi_param_find(params, key); + if (param == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %s\n", key); + return -1; + } + + xfree(param->val); + snprintf(buf, sizeof buf, "%d", val); + param->val = xstrdup(buf); + + return 0; +} + +int +istgt_iscsi_parse_params(ISCSI_PARAM **params, const uint8_t *data, int len) +{ + const uint8_t *p, *q; + const uint8_t *last; + char *key = NULL; + char *val = NULL; + int rc; + int n; + + /* for each key/val temporary store */ + key = xmalloc(ISCSI_TEXT_MAX_KEY_LEN + 1); + val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1); + + /* data = "KEY=VALKEY=VAL..." */ + p = data; + last = data + len; + while (p < last && *p != '\0') { + q = p; + /* q = "KEY=VAL" */ + while (q < last && *q != '\0') { + if (*q == '=') { + break; + } + q++; + } + if (q >= last || *q == '\0') { + ISTGT_ERRLOG("'=' not found\n"); + error_return: + xfree(key); + xfree(val); + return -1; + } + n = q - p; + if (n > ISCSI_TEXT_MAX_KEY_LEN) { + ISTGT_ERRLOG("Overflow Key %d\n", n); + goto error_return; + } + memcpy(key, p, n); + key[n] = '\0'; + + p = q + 1; + q = p; + /* q = "VAL" */ + while (q < last && *q != '\0') { + q++; + } + n = q - p; + if (n > ISCSI_TEXT_MAX_VAL_LEN) { + ISTGT_ERRLOG("Overflow Val %d\n", n); + goto error_return; + } + memcpy(val, p, n); + val[n] = '\0'; + + rc = istgt_iscsi_param_add(params, key, val, NULL, 0); + if (rc < 0) { + ISTGT_ERRLOG("iscsi_param_add() failed\n"); + goto error_return; + } + + p = q + 1; + while (p < last && *p == '\0') { + p++; + } + } + + xfree(key); + xfree(val); + return 0; +} diff --git a/src/istgt_iscsi_param.h b/src/istgt_iscsi_param.h new file mode 100644 index 00000000..c4d5fee8 --- /dev/null +++ b/src/istgt_iscsi_param.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_ISCSI_PARAM_H +#define ISTGT_ISCSI_PARAM_H + +#include + +typedef enum { + ISPT_INVALID = -1, + ISPT_NOTSPECIFIED = 0, + ISPT_LIST, + ISPT_NUMERICAL, + ISPT_NUMERICAL_MAX, + ISPT_DECLARATIVE, + ISPT_BOOLEAN_OR, + ISPT_BOOLEAN_AND, +} ISCSI_PARAM_TYPE; + +typedef struct iscsi_param_t { + struct iscsi_param_t *next; + char *key; + char *val; + char *list; + int type; +} ISCSI_PARAM; + +void istgt_iscsi_param_free(ISCSI_PARAM *params); +ISCSI_PARAM *istgt_iscsi_param_find(ISCSI_PARAM *params, const char *key); +int istgt_iscsi_param_del(ISCSI_PARAM **params, const char *key); +int istgt_iscsi_param_add(ISCSI_PARAM **params, const char *key, const char *val, const char *list, int type); +int istgt_iscsi_param_set(ISCSI_PARAM *params, const char *key, const char *val); +int istgt_iscsi_param_set_int(ISCSI_PARAM *params, const char *key, int val); +int istgt_iscsi_parse_params(ISCSI_PARAM **params, const uint8_t *data, int len); + +#endif /* ISTGT_ISCSI_PARAM_H */ diff --git a/src/istgt_iscsi_xcopy.h b/src/istgt_iscsi_xcopy.h new file mode 100644 index 00000000..37c27215 --- /dev/null +++ b/src/istgt_iscsi_xcopy.h @@ -0,0 +1,70 @@ +/* **************************************************************************** + * (C) Copyright 2014 CloudByte, Inc. + * All Rights Reserved. + * + * This program is an unpublished copyrighted work which is proprietary + * to CloudByte, Inc. and contains confidential information that is not + * to be reproduced or disclosed to any other person or entity without + * prior written consent from CloudByte, Inc. in each and every instance. + * + * WARNING: Unauthorized reproduction of this program as well as + * unauthorized preparation of derivative works based upon the + * program or distribution of copies by sale, rental, lease or + * lending are violations of federal copyright laws and state trade + * secret laws, punishable by civil and criminal penalties. + * + * + ****************************************************************************/ +#ifndef ISTGT_ISCSI_XCOPY_H +#define ISTGT_ISCSI_XCOPY_H + +#include +#include +#include "istgt.h" +#include "istgt_iscsi_param.h" +#include "istgt_iscsi.h" +#include "istgt_scsi.h" +#include "istgt_lu.h" + +#define SNLID 1 /* Support no list id Refer 6.22 / 6.4.3.2 of spc4r36s */ +#define MAX_CSCD_DESCRIPTOR_COUNT 2 +#define MAX_SEGMENT_DESCRIPTOR_COUNT 1 +#define MAX_DESCRIPTOR_LIST_LENGTH 800 +#define MAX_SEGMENT_LENGTH 0 /* No limit on the amount of data written by a single segment */ +#define MAX_INLINE_DATA_LENGTH 0 /* Set to zero since 04h descriptor code not supported */ +#define HELD_DATA_LIMIT 1 +#define MAX_STREAM_DEVICE_TRANSFER_SIZE 0 +#define TOTAL_CONCURRENT_COPIES MAX_CONCURRENT_COPIES /* Since snlid=1 */ +#define MAX_CONCURRENT_COPIES 5 +#define DATA_SEGMENT_GRANULARITY 512 +#define INLINE_DATA_GRANULARITY 512 +#define HELD_DATA_GRANULARITY 512 +#define IMPLEMENTED_DESCRIPTOR_LIST_LENGTH 2 +#define SEGMENT_DESCRIPTOR_B2B 0X2 /* 2d */ +#define SEGMENT_DESCRIPTOR_B2B_OFFSET 0xA /* 10d */ +#define CSCD_IDENTIFICATION_DESCRIPTOR 0xE4 /* 228d */ +#define CSCD_DESCRIPTOR_LENGTH 32 /* 32 bytes */ +#define LIST_ID_USAGE 3 /* 11b */ +#define PARAMETER_HEADER_DATA 16 /* Actual parameter data for copy starts from 16th byte */ +#define NAA_IDENTIFIER 0x03 +#define PDT_DIRECT_ACCESS_BLK_DEV 0x00 +#define PDT_SIMPLIFIED_DIRECT_ACCESS_DEV 0x0E + +typedef struct istgt_xcopy_tgt_t { + ISTGT_LU_DISK *spec; + uint32_t block_len; + uint64_t lba; + uint64_t offset; + int pad; +} ISTGT_XCOPY_TGT; + +int istgt_lu_disk_receive_copy_results(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); +int istgt_lu_disk_xcopy(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); +int istgt_lu_disk_process_xcopy(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data_buf, int dlen); +int istgt_lu_disk_lbxcopy(ISTGT_XCOPY_TGT *src_tgt, ISTGT_XCOPY_TGT *dst_tgt, CONN_Ptr conn, + ISTGT_LU_CMD_Ptr lu_cmd, int dc, int cat, uint64_t num_blks_byts, uint8_t sd_opcode); + + +#endif /* ISTGT_ISCSI_XCOPY_H */ + + diff --git a/src/istgt_log.c b/src/istgt_log.c new file mode 100644 index 00000000..000128c3 --- /dev/null +++ b/src/istgt_log.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "istgt.h" +#include "istgt_log.h" +#include "istgt_misc.h" + +//static int g_trace_flag = 0; +int g_trace_flag = 0; +int g_warn_flag = 1; +static int g_log_facility = ISTGT_LOG_FACILITY; +static int g_log_priority = ISTGT_LOG_PRIORITY; +__thread char tinfo[20] = {0}; +int +istgt_set_log_facility(const char *facility) +{ + if (strcasecmp(facility, "daemon") == 0) { + g_log_facility = LOG_DAEMON; + } else if (strcasecmp(facility, "auth") == 0) { + g_log_facility = LOG_AUTH; + } else if (strcasecmp(facility, "authpriv") == 0) { + g_log_facility = LOG_AUTHPRIV; + } else if (strcasecmp(facility, "local1") == 0) { + g_log_facility = LOG_LOCAL1; + } else if (strcasecmp(facility, "local2") == 0) { + g_log_facility = LOG_LOCAL2; + } else if (strcasecmp(facility, "local3") == 0) { + g_log_facility = LOG_LOCAL3; + } else if (strcasecmp(facility, "local4") == 0) { + g_log_facility = LOG_LOCAL4; + } else if (strcasecmp(facility, "local5") == 0) { + g_log_facility = LOG_LOCAL5; + } else if (strcasecmp(facility, "local6") == 0) { + g_log_facility = LOG_LOCAL6; + } else if (strcasecmp(facility, "local7") == 0) { + g_log_facility = LOG_LOCAL7; + } else { + g_log_facility = ISTGT_LOG_FACILITY; + return -1; + } + return 0; +} + +int +istgt_set_log_priority(const char *priority) +{ + if (strcasecmp(priority, "emerg") == 0) { + g_log_priority = LOG_EMERG; + } else if (strcasecmp(priority, "alert") == 0) { + g_log_priority = LOG_ALERT; + } else if (strcasecmp(priority, "crit") == 0) { + g_log_priority = LOG_CRIT; + } else if (strcasecmp(priority, "err") == 0) { + g_log_priority = LOG_ERR; + } else if (strcasecmp(priority, "warning") == 0) { + g_log_priority = LOG_WARNING; + } else if (strcasecmp(priority, "notice") == 0) { + g_log_priority = LOG_NOTICE; + } else if (strcasecmp(priority, "info") == 0) { + g_log_priority = LOG_INFO; + } else if (strcasecmp(priority, "debug") == 0) { + g_log_priority = LOG_DEBUG; + } else { + g_log_priority = ISTGT_LOG_PRIORITY; + return -1; + } + return 0; +} + +void +istgt_log(const char *file, const int line, const char *func, const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof buf, format, ap); + if (file != NULL) { + if (func != NULL) { + fprintf(stderr, "%s:%4d:%s: %s", file, line, func, buf); + syslog(g_log_priority, "%s:%4d:%s: %s", file, line, func, buf); + } else { + fprintf(stderr, "%s:%4d: %s", file, line, buf); + syslog(g_log_priority, "%s:%4d: %s", file, line, buf); + } + } else { + fprintf(stderr, "%s", buf); + syslog(g_log_priority, "%s", buf); + } + va_end(ap); +} + +void +istgt_noticelog(const char *file, const int line, const char *func, const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof buf, format, ap); + if (file != NULL) { + if (func != NULL) { + fprintf(stderr, "%s:%4d:%s: %s", file, line, func, buf); + syslog(LOG_NOTICE, "%s:%4d:%s: %s", file, line, func, buf); + } else { + fprintf(stderr, "%s:%4d: %s", file, line, buf); + syslog(LOG_NOTICE, "%s:%4d: %s", file, line, buf); + } + } else { + fprintf(stderr, "%s", buf); + syslog(LOG_NOTICE, "%s", buf); + } + va_end(ap); +} + +void +istgt_tracelog(const int flag, const char *file, const int line, const char *func, const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + if (g_trace_flag & flag) { + vsnprintf(buf, sizeof buf, format, ap); + if (func != NULL) { + fprintf(stderr, "%s:%4d:%s: %s", file, line, func, buf); + syslog(LOG_INFO, "%s:%4d:%s: %s", file, line, func, buf); + } else { + fprintf(stderr, "%s:%4d: %s", file, line, buf); + syslog(LOG_INFO, "%s:%4d: %s", file, line, buf); + } + } + va_end(ap); +} + +void +istgt_errlog(const char *file, const int line, const char *func, const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof buf, format, ap); + if (func != NULL) { + fprintf(stderr, "%s:%4d:%s: ***ERROR*** %s", file, line, func, buf); + syslog(LOG_ERR, "%s:%4d:%s: ***ERROR*** %s", file, line, func, buf); + } else { + fprintf(stderr, "%s:%4d: ***ERROR*** %s", file, line, buf); + syslog(LOG_ERR, "%s:%4d: ***ERROR*** %s", file, line, buf); + } + va_end(ap); +} + +void +istgt_warnlog(const char *file, const int line, const char *func, const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof buf, format, ap); + if (func != NULL) { + fprintf(stderr, "%s:%4d:%s: ***WARNING*** %s", file, line, func, buf); + syslog(LOG_WARNING, "%s:%4d:%s: ***WARNING*** %s", + file, line, func, buf); + } else { + fprintf(stderr, "%s:%4d: ***WARNING*** %s", file, line, buf); + syslog(LOG_WARNING, "%s:%4d: ***WARNING*** %s", file, line, buf); + } + va_end(ap); +} + +void +istgt_open_log(void) +{ + if (g_log_facility != 0) { + openlog("istgt", LOG_PID, g_log_facility); + } else { + openlog("istgt", LOG_PID, ISTGT_LOG_FACILITY); + } +} + +void +istgt_close_log(void) +{ + closelog(); +} + +void +istgtcontrol_open_log(void) +{ + if (g_log_facility != 0) { + openlog("istgtcontrol", LOG_PID, g_log_facility); + } else { + openlog("istgtcontrol", LOG_PID, ISTGT_LOG_FACILITY); + } +} + +void +istgtcontrol_close_log(void) +{ + closelog(); +} + +void +istgt_set_trace_flag(int flag) +{ + if (flag == ISTGT_TRACE_NONE) { + g_trace_flag = 0; + } else { + g_trace_flag |= flag; + } +} + +void +istgt_trace_dump(int flag, const char *label, const uint8_t *buf, size_t len) +{ + if (g_trace_flag & flag) { + istgt_fdump(stderr, label, buf, len); + } +} diff --git a/src/istgt_log.h b/src/istgt_log.h new file mode 100644 index 00000000..36fbf29b --- /dev/null +++ b/src/istgt_log.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_LOG_H +#define ISTGT_LOG_H + +#include +#include +#include + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#ifndef ISTGT_LOG_FACILITY +#define ISTGT_LOG_FACILITY LOG_LOCAL7 +#endif +#ifndef ISTGT_LOG_PRIORITY +#define ISTGT_LOG_PRIORITY LOG_NOTICE +#endif + +#define ISTGT_TRACE_ALL (~0U) +#define ISTGT_TRACE_NONE 0U +#define ISTGT_TRACE_DEBUG 0x80000000U +#define ISTGT_TRACE_NET 0x0000000fU +#define ISTGT_TRACE_ISCSI 0x000000f0U +#define ISTGT_TRACE_SCSI 0x00000f00U +#define ISTGT_TRACE_LU 0x0000f000U +#define ISTGT_TRACE_PQ 0x000f0000U +#define ISTGT_TRACE_MEM 0x00f00000U +#define ISTGT_TRACE_PROF 0x01000000U +#define ISTGT_TRACE_PROFX 0x02000000U +#define ISTGT_TRACE_CMD 0x04000000U + +extern __thread char tinfo[20]; +#define ISTGT_LOG(fmt, ...) syslog(LOG_NOTICE, "%-18.18s:%4d: %-20.20s: " fmt, __func__, __LINE__, tinfo, ##__VA_ARGS__) +#define ISTGT_NOTICELOG(fmt, ...) syslog(LOG_NOTICE, "%-18.18s:%4d: %-20.20s: " fmt, __func__, __LINE__, tinfo, ##__VA_ARGS__) +#define ISTGT_ERRLOG(fmt, ...) syslog(LOG_ERR, "%-18.18s:%4d: %-20.20s: " fmt, __func__, __LINE__, tinfo, ##__VA_ARGS__) +#define ISTGT_WARNLOG(fmt, ...) syslog(LOG_ERR, "%-18.18s:%4d: %-20.20s: " fmt, __func__, __LINE__, tinfo, ##__VA_ARGS__) + +#define ISTGT_TRACELOG(FLAG, fmt, ...) \ + do { \ + if (g_trace_flag & FLAG) \ + syslog(LOG_NOTICE, "%-18.18s:%4d: %-20.20s: " fmt, __func__, __LINE__, tinfo, ##__VA_ARGS__); \ + } while (0) +#ifdef DEBUG +#define ISTGT_TRACEDUMP(FLAG, LABEL, BUF, LEN) \ + do { \ + if (g_trace_flag & (FLAG)) { \ + istgt_trace_dump((FLAG), (LABEL), (BUF), (LEN)); \ + } \ + } while (0) +#else +#define ISTGT_TRACEDUMP(FLAG, LABEL, BUF, LEN) +#endif /* DEBUG */ + +int istgt_set_log_facility(const char *facility); +int istgt_set_log_priority(const char *priority); +void istgt_log(const char *file, const int line, const char *func, const char *format, ...) __attribute__((__format__(__printf__, 4, 5))); +void istgt_noticelog(const char *file, const int line, const char *func, const char *format, ...) __attribute__((__format__(__printf__, 4, 5))); +void istgt_tracelog(const int flag, const char *file, const int line, const char *func, const char *format, ...) __attribute__((__format__(__printf__, 5, 6))); +void istgt_errlog(const char *file, const int line, const char *func, const char *format, ...) __attribute__((__format__(__printf__, 4, 5))); +void istgt_warnlog(const char *file, const int line, const char *func, const char *format, ...) __attribute__((__format__(__printf__, 4, 5))); +void istgt_open_log(void); +void istgt_close_log(void); +void istgtcontrol_open_log(void); +void istgtcontrol_close_log(void); +void istgt_set_trace_flag(int flag); +void istgt_trace_dump(int flag, const char *label, const uint8_t *buf, size_t len); + +extern int g_trace_flag; +extern int g_warn_flag; + +#endif /* ISTGT_LOG_H */ diff --git a/src/istgt_lu.c b/src/istgt_lu.c new file mode 100644 index 00000000..1850c300 --- /dev/null +++ b/src/istgt_lu.c @@ -0,0 +1,4648 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_DISK_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif +#ifdef __linux__ +#include +#define pthread_set_name_np pthread_setname_np +#endif + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_conf.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_md5.h" +#include "istgt_iscsi.h" +#include "istgt_lu.h" +#include "istgt_proto.h" +#include "istgt_scsi.h" + +#define MAX_MASKBUF 128 + + +static int +istgt_lu_allow_ipv6(const char *netmask, const char *addr) +{ + struct in6_addr in6_mask; + struct in6_addr in6_addr; + char mask[MAX_MASKBUF]; + const char *p; + size_t n; + int bits, bmask; + int i; + + if (netmask[0] != '[') + return 0; + p = strchr(netmask, ']'); + if (p == NULL) + return 0; + n = p - (netmask + 1); + if (n + 1 > sizeof mask) + return 0; + + memcpy(mask, netmask + 1, n); + mask[n] = '\0'; + p++; + + if (p[0] == '/') { + bits = (int) strtol(p + 1, NULL, 10); + if (bits < 0 || bits > 128) + return 0; + } else { + bits = 128; + } + +#if 0 + printf("input %s\n", addr); + printf("mask %s / %d\n", mask, bits); +#endif + + /* presentation to network order binary */ + if (inet_pton(AF_INET6, mask, &in6_mask) <= 0 + || inet_pton(AF_INET6, addr, &in6_addr) <= 0) { + return 0; + } + + /* check 128bits */ + for (i = 0; i < (bits / 8); i++) { + if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i]) + return 0; + } + if (bits % 8) { + bmask = (0xffU << (8 - (bits % 8))) & 0xffU; + if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask)) + return 0; + } + + /* match */ + return 1; +} + +static int +istgt_lu_allow_ipv4(const char *netmask, const char *addr) +{ + struct in_addr in4_mask; + struct in_addr in4_addr; + char mask[MAX_MASKBUF]; + const char *p; + uint32_t bmask; + size_t n; + int bits; + + p = strchr(netmask, '/'); + if (p == NULL) { + p = netmask + strlen(netmask); + } + n = p - netmask; + if (n + 1 > sizeof mask) + return 0; + + memcpy(mask, netmask, n); + mask[n] = '\0'; + + if (p[0] == '/') { + bits = (int) strtol(p + 1, NULL, 10); + if (bits < 0 || bits > 32) + return 0; + } else { + bits = 32; + } + +#if 0 + printf("input %s\n", addr); + printf("mask %s / %d\n", mask, bits); +#endif + + /* presentation to network order binary */ + if (inet_pton(AF_INET, mask, &in4_mask) <= 0 + || inet_pton(AF_INET, addr, &in4_addr) <= 0) { + return 0; + } + + /* check 32bits */ + bmask = (0xffffffffU << (32 - bits)) & 0xffffffffU; + if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask)) + return 0; + + /* match */ + return 1; +} + +int +istgt_lu_allow_netmask(const char *netmask, const char *addr) +{ + if (netmask == NULL || addr == NULL) + return 0; + if (strcasecmp(netmask, "ALL") == 0) + return 1; + if (netmask[0] == '[') { + /* IPv6 */ + if (istgt_lu_allow_ipv6(netmask, addr)) + return 1; + } else { + /* IPv4 */ + if (istgt_lu_allow_ipv4(netmask, addr)) + return 1; + } + return 0; +} + +/* Print the connection status to a logfile */ +void +istgt_connection_status(CONN_Ptr conn, const char *status) +{ + FILE *fp; + char *logfile = NULL; + time_t current_time; + char* c_time_string; + char *time_val; + + /* Obtain current time as seconds elapsed since the Epoch. */ + current_time = time(NULL); + + /* Convert to local time format. */ + c_time_string = ctime(¤t_time); + time_val = strtok(c_time_string, "\n"); + MTX_LOCK(&conn->istgt->mutex); + logfile = xstrdup(conn->istgt->logfile); + MTX_UNLOCK(&conn->istgt->mutex); + fp = fopen (logfile, "a"); + if (fp == NULL) { + fprintf(stderr, "Cannot open the file %s \n", logfile); + return; + } + fprintf(fp,"%s From %s To %s : %s\n", time_val, conn->initiator_name, conn->target_name, status); + fclose(fp); + xfree(logfile); +} + +int +istgt_lu_access(CONN_Ptr conn, ISTGT_LU_Ptr lu, const char *iqn, const char *addr) +{ + ISTGT_Ptr istgt; + INITIATOR_GROUP *igp; + int pg_tag; + int ig_tag; + int rc; + int i, j, k; + + if (conn == NULL || lu == NULL || iqn == NULL || addr == NULL) + return 0; + istgt = conn->istgt; + pg_tag = conn->portal.tag; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pg=%d, iqn=%s, addr=%s\n", + pg_tag, iqn, addr); + for (i = 0; i < lu->maxmap; i++) { + /* skip excluding self portal group tag */ + if (pg_tag != lu->map[i].pg_tag) + continue; + /* iqn is initiator group? */ + ig_tag = lu->map[i].ig_tag; + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag); + if (igp == NULL) { + ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num); + continue; + } + for (j = 0; j < igp->ninitiators; j++) { + /* deny initiators */ + if (igp->initiators[j][0] == '!' + && (strcasecmp(&igp->initiators[j][1], "ALL") == 0 + || strcasecmp(&igp->initiators[j][1], iqn) == 0)) { + /* NG */ + MTX_UNLOCK(&conn->istgt->mutex); + istgt_connection_status(conn, "ACCESS DENIED"); + MTX_LOCK(&conn->istgt->mutex); + ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n", + iqn, addr, conn->target_name, conn->portal.host, + conn->portal.port, conn->portal.tag); + return 0; + } + /* allow initiators */ + if (strcasecmp(igp->initiators[j], "ALL") == 0 + || strcasecmp(igp->initiators[j], iqn) == 0) { + /* OK iqn, check netmask */ + if (igp->nnetmasks == 0) { + /* OK, empty netmask as ALL */ + return 1; + } + for (k = 0; k < igp->nnetmasks; k++) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "netmask=%s, addr=%s\n", + igp->netmasks[k], addr); + rc = istgt_lu_allow_netmask(igp->netmasks[k], addr); + if (rc > 0) { + /* OK netmask */ + return 1; + } + } + /* NG netmask in this group */ + } + } + } + + /* NG */ + MTX_UNLOCK(&conn->istgt->mutex); + istgt_connection_status(conn, "ACCESS DENIED"); + MTX_LOCK(&conn->istgt->mutex); + ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n", + iqn, addr, conn->target_name, conn->portal.host, + conn->portal.port, conn->portal.tag); + return 0; +} + +int +istgt_lu_visible(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu, const char *iqn, int pg_tag) +{ + INITIATOR_GROUP *igp; + int match_pg_tag; + int ig_tag; + int i, j; + + if (istgt == NULL || lu == NULL || iqn == NULL) + return 0; + /* pg_tag exist map? */ + match_pg_tag = 0; + for (i = 0; i < lu->maxmap; i++) { + if (lu->map[i].pg_tag == pg_tag) { + match_pg_tag = 1; + break; + } + } + if (match_pg_tag == 0) { + /* cat't access from pg_tag */ + return 0; + } + for (i = 0; i < lu->maxmap; i++) { + /* iqn is initiator group? */ + ig_tag = lu->map[i].ig_tag; + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag); + if (igp == NULL) { + ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num); + continue; + } + for (j = 0; j < igp->ninitiators; j++) { + if (igp->initiators[j][0] == '!' + && (strcasecmp(&igp->initiators[j][1], "ALL") == 0 + || strcasecmp(&igp->initiators[j][1], iqn) == 0)) { + /* NG */ + return 0; + } + if (strcasecmp(igp->initiators[j], "ALL") == 0 + || strcasecmp(igp->initiators[j], iqn) == 0) { + /* OK iqn, no check addr */ + return 1; + } + } + } + + /* NG */ + return 0; +} + +static int +istgt_pg_visible(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu, const char *iqn, int pg_tag) +{ + INITIATOR_GROUP *igp; + int match_idx; + int ig_tag; + int i, j; + + if (istgt == NULL || lu == NULL || iqn == NULL) + return 0; + match_idx = -1; + for (i = 0; i < lu->maxmap; i++) { + if (lu->map[i].pg_tag == pg_tag) { + match_idx = i; + break; + } + } + if (match_idx < 0) { + /* cant't find pg_tag */ + return 0; + } + + /* iqn is initiator group? */ + ig_tag = lu->map[match_idx].ig_tag; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "iqn=%s, pg=%d, ig=%d\n", iqn, pg_tag, ig_tag); + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag); + if (igp == NULL) { + ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num); + return 0; + } + for (j = 0; j < igp->ninitiators; j++) { + if (igp->initiators[j][0] == '!' + && (strcasecmp(&igp->initiators[j][1], "ALL") == 0 + || strcasecmp(&igp->initiators[j][1], iqn) == 0)) { + /* NG */ + return 0; + } + if (strcasecmp(igp->initiators[j], "ALL") == 0 + || strcasecmp(igp->initiators[j], iqn) == 0) { + /* OK iqn, no check addr */ + return 1; + } + } + + /* NG */ + return 0; +} + +int +istgt_lu_sendtargets(CONN_Ptr conn, const char *iiqn, const char *iaddr, const char *tiqn, uint8_t *data, int alloc_len, int data_len) +{ + char buf[MAX_TMPBUF]; + ISTGT_Ptr istgt; + ISTGT_LU_Ptr lu; + char *host; + int total; + int len; + int rc; + int pg_tag; + int i, j, k, l; + + if (conn == NULL) + return 0; + istgt = conn->istgt; + + total = data_len; + if (alloc_len < 1) { + return 0; + } + if (total > alloc_len) { + total = alloc_len; + data[total - 1] = '\0'; + return total; + } + + if (alloc_len - total < 1) { + ISTGT_ERRLOG("data space small %d\n", alloc_len); + return total; + } + + MTX_LOCK(&istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (strcasecmp(tiqn, "ALL") != 0 + && strcasecmp(tiqn, lu->name) != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "SKIP iqn=%s for %s from %s (%s)\n", + tiqn, lu->name, iiqn, iaddr); + continue; + } + rc = istgt_lu_visible(istgt, lu, iiqn, conn->portal.tag); + if (rc == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "SKIP iqn=%s for %s from %s (%s)\n", + tiqn, lu->name, iiqn, iaddr); + continue; + } + + /* DO SENDTARGETS */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "OK iqn=%s for %s from %s (%s)\n", + tiqn, lu->name, iiqn, iaddr); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "TargetName=%s\n", lu->name); + len = snprintf((char *) data + total, alloc_len - total, + "TargetName=%s", lu->name); + total += len + 1; + + for (j = 0; j < lu->maxmap; j++) { + pg_tag = lu->map[j].pg_tag; + /* skip same pg_tag */ + for (k = 0; k < j; k++) { + if (lu->map[k].pg_tag == pg_tag) { + goto skip_pg_tag; + } + } + rc = istgt_pg_visible(istgt, lu, iiqn, pg_tag); + if (rc == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "SKIP pg=%d, iqn=%s for %s from %s (%s)\n", + pg_tag, tiqn, lu->name, iiqn, iaddr); + goto skip_pg_tag; + } + + /* write to data */ + for (k = 0; k < istgt->nportal_group; k++) { + if (istgt->portal_group[k].tag != pg_tag) + continue; + for (l = 0; l < istgt->portal_group[k].nportals; l++) { + if (alloc_len - total < 1) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("data space small %d\n", + alloc_len); + return total; + } + host = istgt->portal_group[k].portals[l]->host; + /* wildcard? */ + if (strcasecmp(host, "[::]") == 0 + || strcasecmp(host, "[*]") == 0 + || strcasecmp(host, "0.0.0.0") == 0 + || strcasecmp(host, "*") == 0) { + if ((strcasecmp(host, "[::]") == 0 + || strcasecmp(host, "[*]") == 0) + && conn->initiator_family == AF_INET6) { + snprintf(buf, sizeof buf, "[%s]", + conn->target_addr); + host = buf; + } else if ((strcasecmp(host, "0.0.0.0") == 0 + || strcasecmp(host, "*") == 0) + && conn->initiator_family == AF_INET) { + snprintf(buf, sizeof buf, "%s", + conn->target_addr); + host = buf; + } else { + /* skip portal for the family */ + continue; + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "TargetAddress=%s:%s,%d\n", + host, + istgt->portal_group[k].portals[l]->port, + istgt->portal_group[k].portals[l]->tag); + len = snprintf((char *) data + total, + alloc_len - total, + "TargetAddress=%s:%s,%d", + host, + istgt->portal_group[k].portals[l]->port, + istgt->portal_group[k].portals[l]->tag); + total += len + 1; + } + } + skip_pg_tag: + ; + } + } + MTX_UNLOCK(&istgt->mutex); + + return total; +} + +ISTGT_LU_Ptr +istgt_lu_find_target(ISTGT_Ptr istgt, const char *target_name) +{ + ISTGT_LU_Ptr lu; + int i; + + if (istgt == NULL || target_name == NULL) + return NULL; + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (strcasecmp(target_name, lu->name) == 0) { + return lu; + } + } + ISTGT_WARNLOG("can't find target %s\n", + target_name); + return NULL; +} + +int +istgt_lu_add_nexus(ISTGT_LU_Ptr lu, char *initiator_port) +{ + int lun = 0, rc = 0; + + if (lu == NULL ||initiator_port == NULL) + return -1; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_add_nexus LU%d Initiator %s\n", lu->num, initiator_port); + /* Add the nexus for each Disk */ + for (lun = 0; lun < lu->maxlun; lun++) { + if (lu->type == ISTGT_LU_TYPE_DISK) + rc = istgt_lu_disk_add_nexus(lu, lun, initiator_port); + } + return rc; +} + +int +istgt_lu_remove_nexus(ISTGT_LU_Ptr lu, char* initiator_port) +{ + int lun = 0, rc = 0; + + if (lu == NULL || initiator_port == NULL) + return -1; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"istgt_lu_remove_nexus LU%d Initiator %s \n", lu->num, initiator_port); + for (lun = 0; lun < lu->maxlun; lun++) { + if (lu->type == ISTGT_LU_TYPE_DISK) + rc = istgt_lu_disk_remove_nexus(lu, lun, initiator_port); + } + + return rc; + } + +uint16_t +istgt_lu_allocate_tsih(ISTGT_LU_Ptr lu, const char *initiator_port, int tag) +{ + uint16_t tsih; + int retry = 10; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_allocate_tsih\n"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "initiator_port=%s, tag=%d\n", + initiator_port, tag); + if (lu == NULL || initiator_port == NULL || tag == 0) + return 0; + /* tsih 0 is reserved */ + tsih = 0; +#if 0 + for (i = 1; i < MAX_LU_TSIH; i++) { + if (lu->tsih[i].initiator_port == NULL) + continue; + if (tag != lu->tsih[i].tag) + continue; + if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) { + tsih = lu->tsih[i].tsih; + break; + } + } +#endif + if (tsih == 0) { + if (lu->maxtsih >= MAX_LU_TSIH) { + ISTGT_ERRLOG("LU%d: tsih is maximum\n", lu->num); + return 0; + } + retry: + lu->last_tsih++; + tsih = lu->last_tsih; + if (tsih == 0) { + if (retry > 0) { + retry--; + goto retry; + } + ISTGT_ERRLOG("LU%d: retry error\n", lu->num); + return 0; + } + for (i = 1; i < MAX_LU_TSIH; i++) { + if (lu->tsih[i].initiator_port != NULL + && lu->tsih[i].tsih == tsih) { + ISTGT_ERRLOG("tsih is found in list\n"); + if (retry > 0) { + retry--; + goto retry; + } + ISTGT_ERRLOG("LU%d: retry error\n", lu->num); + return 0; + } + } + for (i = 1; i < MAX_LU_TSIH; i++) { + if (lu->tsih[i].initiator_port == NULL) { + lu->tsih[i].tag = tag; + lu->tsih[i].tsih = tsih; + lu->tsih[i].initiator_port = xstrdup(initiator_port); + lu->maxtsih++; + break; + } + } + } + return tsih; +} + +void +istgt_lu_free_tsih(ISTGT_LU_Ptr lu, uint16_t tsih, char *initiator_port) +{ + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_free_tsih\n"); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "tsih=%u, initiator_port=%s\n", + tsih, initiator_port); + if (lu == NULL || initiator_port == NULL) + return; + if (tsih == 0) + return; + + MTX_LOCK(&lu->mutex); + for (i = 1; i < MAX_LU_TSIH; i++) { + if (lu->tsih[i].initiator_port == NULL) + continue; + if (lu->tsih[i].tsih != tsih) + continue; + + if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) { + lu->tsih[i].tag = 0; + lu->tsih[i].tsih = 0; + xfree(lu->tsih[i].initiator_port); + lu->tsih[i].initiator_port = NULL; + lu->maxtsih--; + break; + } + } + MTX_UNLOCK(&lu->mutex); + return; +} + +char * +istgt_lu_get_media_flags_string(int flags, char *buf, size_t len) +{ + char *p; + size_t rest; + + p = buf; + rest = len; + if (flags & ISTGT_LU_FLAG_MEDIA_READONLY) { + snprintf(p, rest, "%s", "ro"); + } else { + snprintf(p, rest, "%s", "rw"); + } + p = buf + strlen(buf); + rest = len - strlen(buf); + if (flags & ISTGT_LU_FLAG_MEDIA_EXTEND) { + snprintf(p, rest, ",%s", "extend"); + } + p = buf + strlen(buf); + rest = len - strlen(buf); + if (flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) { + snprintf(p, rest, ",%s", "dynamic"); + } + return buf; +} + +uint64_t +istgt_lu_get_devsize(const char *file) +{ + uint64_t val; + struct stat st; + int fd; + int rc; + + val = 0ULL; +#ifdef ALLOW_SYMLINK_DEVICE + rc = stat(file, &st); +#else + rc = lstat(file, &st); +#endif /* ALLOW_SYMLINK_DEVICE */ + if (rc != 0) + return val; + if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) + return val; + + fd = open(file, O_RDONLY, 0); + if (fd >= 0) { +#ifdef DIOCGMEDIASIZE + if (val == 0) { + off_t offset; + rc = ioctl(fd, DIOCGMEDIASIZE, &offset); + if (rc != -1) { + val = (uint64_t) offset; + } + } +#endif /* DIOCGMEDIASIZE */ +#ifdef DIOCGDINFO + if (val == 0) { + struct disklabel dl; + rc = ioctl(fd, DIOCGDINFO, &dl); + if (rc != -1) { + val = (uint64_t) dl.d_secperunit; + val *= (uint64_t) dl.d_secsize; + } + } +#endif /* DIOCGDINFO */ +#if defined(DKIOCGETBLOCKSIZE) && defined(DKIOCGETBLOCKCOUNT) + if (val == 0) { + uint32_t blocklen; + uint64_t blockcnt; + rc = ioctl(fd, DKIOCGETBLOCKSIZE, &blocklen); + if (rc != -1) { + rc = ioctl(fd, DKIOCGETBLOCKCOUNT, &blockcnt); + if (rc != -1) { + val = (uint64_t) blocklen; + val *= (uint64_t) blockcnt; + } + } + } +#endif /* DKIOCGETBLOCKSIZE && DKIOCGETBLOCKCOUNT */ +#ifdef __linux__ +#ifdef BLKGETSIZE64 + if (val == 0) { + uint64_t blocksize; + rc = ioctl(fd, BLKGETSIZE64, &blocksize); + if (rc != -1) { + val = (uint64_t) blocksize; + } + } +#endif /* BLKGETSIZE64 */ +#ifdef BLKGETSIZE + if (val == 0) { + uint32_t blocksize; + rc = ioctl(fd, BLKGETSIZE, &blocksize); + if (rc != -1) { + val = (uint64_t) 512; + val *= (uint64_t) blocksize; + } + } +#endif /* BLKGETSIZE */ +#endif /* __linux__ */ + if (val == 0) { + ISTGT_ERRLOG("unknown device size\n"); + } + (void) close(fd); + } else { + if (g_trace_flag) { + ISTGT_WARNLOG("open error %s (errno=%d)\n", file, errno); + } + val = 0ULL; + } + return val; +} + + + +uint64_t +istgt_lu_get_filesize(const char *file) +{ + uint64_t val; + struct stat st; + int rc; + + val = 0ULL; +#ifdef ALLOW_SYMLINK_DEVICE + rc = stat(file, &st); +#else + rc = lstat(file, &st); +#endif /* ALLOW_SYMLINK_DEVICE */ + + if (rc < 0) + return val; +#ifndef ALLOW_SYMLINK_DEVICE + if (S_ISLNK(st.st_mode)) + return val; +#endif /* ALLOW_SYMLINK_DEVICE */ + if (S_ISCHR(st.st_mode)) { + val = istgt_lu_get_devsize(file); + } else if (S_ISBLK(st.st_mode)) { + val = istgt_lu_get_devsize(file); + } else if (S_ISREG(st.st_mode)) { + val = st.st_size; + } else { +#ifdef ALLOW_SYMLINK_DEVICE + ISTGT_ERRLOG("stat is neither REG, CHR nor BLK\n"); +#else + ISTGT_ERRLOG("lstat is neither REG, CHR nor BLK\n"); +#endif /* ALLOW_SYMLINK_DEVICE */ + val = 0ULL; + } + return val; +} + + +uint64_t +istgt_lu_parse_size(const char *size) +{ + uint64_t val, val1, val2; + char *endp, *p; + size_t idx; + int sign; + + val1 = (uint64_t) strtoull(size, &endp, 10); + val = val1; + val2 = 0; + if (endp != NULL) { + p = endp; + switch (toupper((int) *p)) { + case 'Z': val1 *= (uint64_t) 1024ULL; + case 'E': val1 *= (uint64_t) 1024ULL; + case 'P': val1 *= (uint64_t) 1024ULL; + case 'T': val1 *= (uint64_t) 1024ULL; + case 'G': val1 *= (uint64_t) 1024ULL; + case 'M': val1 *= (uint64_t) 1024ULL; + case 'K': val1 *= (uint64_t) 1024ULL; + break; + } + val = val1; + p++; + idx = strspn(p, "Bb \t"); + p += idx; + if (*p == '-' || *p == '+') { + sign = (int) *p++; + idx = strspn(p, " \t"); + p += idx; + val2 = (uint64_t) strtoull(p, &endp, 10); + if (endp != NULL) { + p = endp; + switch (toupper((int) *p)) { + case 'Z': val2 *= (uint64_t) 1024ULL; + case 'E': val2 *= (uint64_t) 1024ULL; + case 'P': val2 *= (uint64_t) 1024ULL; + case 'T': val2 *= (uint64_t) 1024ULL; + case 'G': val2 *= (uint64_t) 1024ULL; + case 'M': val2 *= (uint64_t) 1024ULL; + case 'K': val2 *= (uint64_t) 1024ULL; + break; + } + } + if (sign == '-') { + if (val2 > val1) { + /* underflow */ + val = (uint64_t) 0ULL; + } else { + val = val1 - val2; + } + } else { + if (val2 > (UINT64_MAX - val1)) { + /* overflow */ + val = UINT64_MAX; + } else { + val = val1 + val2; + } + } + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "size=%s, val=%"PRIu64", val1=%"PRIu64", val2=%"PRIu64"\n", + size, val, val1, val2); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "size=%s, val=%"PRIx64", val1=%"PRIx64", val2=%"PRIx64"\n", + size, val, val1, val2); + + return val; +} + +int +istgt_lu_parse_media_flags(const char *flags) +{ + char buf[MAX_TMPBUF]; + const char *delim = ","; + char *next_p; + char *p; + int mflags; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "mflags=%s\n", flags); + mflags = 0; + strlcpy(buf, flags, MAX_TMPBUF); + next_p = buf; + while ((p = strsep(&next_p, delim)) != NULL) { + if (strcasecmp(p, "ro") == 0) { + mflags |= ISTGT_LU_FLAG_MEDIA_READONLY; + } else if (strcasecmp(p, "rw") == 0) { + mflags &= ~ISTGT_LU_FLAG_MEDIA_READONLY; + } else if (strcasecmp(p, "extend") == 0) { + mflags |= ISTGT_LU_FLAG_MEDIA_EXTEND; + } else if (strcasecmp(p, "dynamic") == 0) { + mflags |= ISTGT_LU_FLAG_MEDIA_DYNAMIC; + } else { + ISTGT_ERRLOG("unknown media flag %.64s\n", p); + } + } + + return mflags; +} + +uint64_t +istgt_lu_parse_media_size(const char *file, const char *size, int *flags) +{ + uint64_t msize, fsize; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "msize=%s\n", size); + if (strcasecmp(file, "/dev/null") == 0) { + return 0; + } + if (strcasecmp(size, "Auto") == 0 + || strcasecmp(size, "Size") == 0) { + msize = istgt_lu_get_filesize(file); + if (msize == 0) { + msize = ISTGT_LU_MEDIA_SIZE_MIN; + } + *flags |= ISTGT_LU_FLAG_MEDIA_AUTOSIZE; + } else { + msize = istgt_lu_parse_size(size); + if (*flags & ISTGT_LU_FLAG_MEDIA_EXTEND) { + fsize = istgt_lu_get_filesize(file); + if (fsize > msize) { + msize = fsize; + } + } + } + + if (*flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) { + if (msize < ISTGT_LU_MEDIA_SIZE_MIN) { + msize = ISTGT_LU_MEDIA_SIZE_MIN; + } + } else { + if (msize < ISTGT_LU_MEDIA_SIZE_MIN) { + ISTGT_ERRLOG("media size too small\n"); + return 0ULL; + } + } + + return msize; +} + +PORTAL_GROUP * +istgt_lu_find_portalgroup(ISTGT_Ptr istgt, int tag) +{ + PORTAL_GROUP *pgp; + int i; + + for (i = 0; i < istgt->nportal_group; i++) { + if (istgt->portal_group[i].tag == tag) { + pgp = &istgt->portal_group[i]; + return pgp; + } + } + return NULL; +} + +INITIATOR_GROUP * +istgt_lu_find_initiatorgroup(ISTGT_Ptr istgt, int tag) +{ + INITIATOR_GROUP *igp; + int i; + + for (i = 0; i < istgt->ninitiator_group; i++) { + if (istgt->initiator_group[i].tag == tag) { + igp = &istgt->initiator_group[i]; + return igp; + } + } + return NULL; +} + +static int +istgt_lu_check_iscsi_name(const char *name) +{ + const unsigned char *up = (const unsigned char *) name; + size_t n; + + /* valid iSCSI name? */ + for (n = 0; up[n] != 0; n++) { + if (up[n] > 0x00U && up[n] <= 0x2cU) + return -1; + if (up[n] == 0x2fU) + return -1; + if (up[n] >= 0x3bU && up[n] <= 0x40U) + return -1; + if (up[n] >= 0x5bU && up[n] <= 0x60U) + return -1; + if (up[n] >= 0x7bU && up[n] <= 0x7fU) + return -1; + if (isspace(up[n])) + return -1; + } + /* valid format? */ + if (strncasecmp(name, "iqn.", 4) == 0) { + /* iqn.YYYY-MM.reversed.domain.name */ + if (!isdigit(up[4]) || !isdigit(up[5]) || !isdigit(up[6]) + || !isdigit(up[7]) || up[8] != '-' || !isdigit(up[9]) + || !isdigit(up[10]) || up[11] != '.') { + ISTGT_ERRLOG("invalid iqn format. " + "expect \"iqn.YYYY-MM.reversed.domain.name\"\n"); + return -1; + } + } else if (strncasecmp(name, "eui.", 4) == 0) { + /* EUI-64 -> 16bytes */ + /* XXX */ + } else if (strncasecmp(name, "naa.", 4) == 0) { + /* 64bit -> 16bytes, 128bit -> 32bytes */ + /* XXX */ + } + /* OK */ + return 0; +} + +#if 0 +static uint64_t +istgt_lu_get_nbserial(const char *nodebase) +{ + ISTGT_MD5CTX md5ctx; + uint8_t nbsmd5[ISTGT_MD5DIGEST_LEN]; + char buf[MAX_TMPBUF]; + uint64_t nbs; + int idx; + int i; + + snprintf(buf, sizeof buf, "%s", nodebase); + if (strcasecmp(buf, "iqn.2007-09.jp.ne.peach.istgt") == 0 + || strcasecmp(buf, "iqn.2007-09.jp.ne.peach") == 0) { + /* always zero */ + return 0; + } + + istgt_md5init(&md5ctx); + istgt_md5update(&md5ctx, buf, strlen(buf)); + istgt_md5final(nbsmd5, &md5ctx); + + nbs = 0U; + idx = ISTGT_MD5DIGEST_LEN - 8; + if (idx < 0) { + ISTGT_WARNLOG("missing MD5 length\n"); + idx = 0; + } + for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) { + nbs |= (uint64_t) nbsmd5[i]; + nbs = nbs << 8; + } + return nbs; +} +#endif + +static int +istgt_lu_set_local_settings(ISTGT_Ptr istgt, CF_SECTION *sp, ISTGT_LU_Ptr lu) +{ + const char *val; + + val = istgt_get_val(sp, "MaxOutstandingR2T"); + if (val == NULL) { + lu->MaxOutstandingR2T = lu->istgt->MaxOutstandingR2T; + } else { + lu->MaxOutstandingR2T = (int)strtol(val, NULL, 10); + if (lu->MaxOutstandingR2T < 1) { + lu->MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n", + lu->MaxOutstandingR2T); + } + + val = istgt_get_val(sp, "DefaultTime2Wait"); + if (val == NULL) { + lu->DefaultTime2Wait = lu->istgt->DefaultTime2Wait; + } else { + lu->DefaultTime2Wait = (int)strtol(val, NULL, 10); + if (lu->DefaultTime2Wait < 0) { + lu->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n", + lu->DefaultTime2Wait); + } + + val = istgt_get_val(sp, "DefaultTime2Retain"); + if (val == NULL) { + lu->DefaultTime2Retain = lu->istgt->DefaultTime2Retain; + } else { + lu->DefaultTime2Retain = (int)strtol(val, NULL, 10); + if (lu->DefaultTime2Retain < 0) { + lu->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n", + lu->DefaultTime2Retain); + } + + /* check size limit - RFC3720(12.15, 12.16, 12.17) */ + if (lu->MaxOutstandingR2T > 65535) { + ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n", + lu->MaxOutstandingR2T); + return -1; + } + if (lu->DefaultTime2Wait > 3600) { + ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n", + lu->DefaultTime2Wait); + return -1; + } + if (lu->DefaultTime2Retain > 3600) { + ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n", + lu->DefaultTime2Retain); + return -1; + } + + val = istgt_get_val(sp, "FirstBurstLength"); + if (val == NULL) { + lu->FirstBurstLength = lu->istgt->FirstBurstLength; + } else { + lu->FirstBurstLength = (int)strtol(val, NULL, 10); + if (lu->FirstBurstLength < 0) { + lu->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n", + lu->FirstBurstLength); + } + + val = istgt_get_val(sp, "MaxBurstLength"); + if (val == NULL) { + lu->MaxBurstLength = lu->istgt->MaxBurstLength; + } else { + lu->MaxBurstLength = (int)strtol(val, NULL, 10); + if (lu->MaxBurstLength < 0) { + lu->MaxBurstLength = DEFAULT_MAXBURSTLENGTH; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n", + lu->MaxBurstLength); + } + + val = istgt_get_val(sp, "MaxRecvDataSegmentLength"); + if (val == NULL) { + lu->MaxRecvDataSegmentLength + = lu->istgt->MaxRecvDataSegmentLength; + } else { + lu->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); + if (lu->MaxRecvDataSegmentLength < 0) { + lu->MaxRecvDataSegmentLength + = DEFAULT_MAXRECVDATASEGMENTLENGTH; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "MaxRecvDataSegmentLength %d\n", + lu->MaxRecvDataSegmentLength); + } + + /* check size limit (up to 24bits - RFC3720(12.12)) */ + if (lu->MaxBurstLength < 512) { + ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n", + lu->MaxBurstLength); + return -1; + } + if (lu->FirstBurstLength < 512) { + ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n", + lu->FirstBurstLength); + return -1; + } + if (lu->FirstBurstLength > lu->MaxBurstLength) { + ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n", + lu->FirstBurstLength, istgt->MaxBurstLength); + return -1; + } + if (lu->MaxBurstLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n", + lu->MaxBurstLength); + return -1; + } + if (lu->MaxRecvDataSegmentLength < 512) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n", + lu->MaxRecvDataSegmentLength); + return -1; + } + if (lu->MaxRecvDataSegmentLength > 0x00ffffff) { + ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n", + lu->MaxRecvDataSegmentLength); + return -1; + } + + val = istgt_get_val(sp, "InitialR2T"); + if (val == NULL) { + lu->InitialR2T = lu->istgt->InitialR2T; + } else { + if (strcasecmp(val, "Yes") == 0) { + lu->InitialR2T = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + lu->InitialR2T = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n", + lu->InitialR2T ? "Yes" : "No"); + } + + val = istgt_get_val(sp, "ImmediateData"); + if (val == NULL) { + lu->ImmediateData = lu->istgt->ImmediateData; + } else { + if (strcasecmp(val, "Yes") == 0) { + lu->ImmediateData = 1; + } else if (strcasecmp(val, "No") == 0) { + lu->ImmediateData = 0; + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n", + lu->ImmediateData ? "Yes" : "No"); + } + + val = istgt_get_val(sp, "DataPDUInOrder"); + if (val == NULL) { + lu->DataPDUInOrder = lu->istgt->DataPDUInOrder; + } else { + if (strcasecmp(val, "Yes") == 0) { + lu->DataPDUInOrder = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + lu->DataPDUInOrder = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n", + lu->DataPDUInOrder ? "Yes" : "No"); + } + + val = istgt_get_val(sp, "DataSequenceInOrder"); + if (val == NULL) { + lu->DataSequenceInOrder = lu->istgt->DataSequenceInOrder; + } else { + if (strcasecmp(val, "Yes") == 0) { + lu->DataSequenceInOrder = 1; + } else if (strcasecmp(val, "No") == 0) { +#if 0 + lu->DataSequenceInOrder = 0; +#else + ISTGT_ERRLOG("not supported value %s\n", val); + return -1; +#endif + } else { + ISTGT_ERRLOG("unknown value %s\n", val); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n", + lu->DataSequenceInOrder ? "Yes" : "No"); + } + + val = istgt_get_val(sp, "ErrorRecoveryLevel"); + if (val == NULL) { + lu->ErrorRecoveryLevel = lu->istgt->ErrorRecoveryLevel; + } else { + lu->ErrorRecoveryLevel = (int)strtol(val, NULL, 10); + if (lu->ErrorRecoveryLevel < 0) { + lu->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL; + } else if (lu->ErrorRecoveryLevel == 0) { + lu->ErrorRecoveryLevel = 0; + } else if (lu->ErrorRecoveryLevel == 1) { +#if 0 + lu->ErrorRecoveryLevel = 1; +#else + ISTGT_ERRLOG("not supported value %d\n", + lu->ErrorRecoveryLevel); + return -1; +#endif + } else if (lu->ErrorRecoveryLevel == 2) { +#if 0 + lu->ErrorRecoveryLevel = 2; +#else + ISTGT_ERRLOG("not supported value %d\n", + lu->ErrorRecoveryLevel); + return -1; +#endif + } else { + ISTGT_ERRLOG("not supported value %d\n", + lu->ErrorRecoveryLevel); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n", + istgt->ErrorRecoveryLevel); + } + + return 0; +} + +extern int g_num_luworkers; + +static int +istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SECTION *sp) +{ + char buf[MAX_TMPBUF], buf2[MAX_TMPBUF]; + ISTGT_LU_Ptr lu; + PORTAL_GROUP *pgp; + INITIATOR_GROUP *igp; + const char *vendor, *product, *revision, *serial; + const char *pg_tag, *ig_tag; + const char *ag_tag; + const char *flags, *file, *size, *rsz; + const char *key, *val; + uint64_t msize; + //uint64_t nbs64; + int pg_tag_i, ig_tag_i; + int ag_tag_i; + int rpm, formfactor, opt_tlen; + int mflags; + int slot; + int nbs; + int i, j, k; + int rc; + int gotstorage = 0; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add unit %d\n", sp->num); + + if (sp->num >= MAX_LOGICAL_UNIT) { + ISTGT_ERRLOG("LU%d: over maximum unit number\n", sp->num); + return -1; + } + if (istgt->logical_unit[sp->num] != NULL) { + ISTGT_ERRLOG("LU%d: duplicate unit\n", sp->num); + return -1; + } + + lu = xmalloc(sizeof *lu); + memset(lu, 0, sizeof *lu); + lu->num = sp->num; + lu->istgt = istgt; + lu->state = ISTGT_STATE_INVALID; +#if 0 + /* disabled now */ + nbs64 = istgt_lu_get_nbserial(istgt->nodebase); + nbs = (int) (nbs64 % 900) * 100000; +#else + nbs = 0; +#endif + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + val = istgt_get_val(sp, "TargetName"); + if (val == NULL) { + ISTGT_ERRLOG("LU%d: TargetName not found\n", lu->num); + goto error_return; + } + if (strncasecmp(val, "iqn.", 4) != 0 + && strncasecmp(val, "eui.", 4) != 0 + && strncasecmp(val, "naa.", 4) != 0) { + snprintf(buf, sizeof buf, "%s:%s", istgt->nodebase, val); + } else { + snprintf(buf, sizeof buf, "%s", val); + } + if (istgt_lu_check_iscsi_name(buf) != 0) { + ISTGT_ERRLOG("TargetName %s contains an invalid character or format.\n", + buf); +#if 0 + goto error_return; +#endif + } + lu->name = xstrdup(buf); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetName %s\n", + lu->name); + + val = istgt_get_val(sp, "TargetAlias"); + if (val == NULL) { + lu->alias = NULL; + } else { + lu->alias = xstrdup(val); + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetAlias %s\n", + lu->alias); + + val = istgt_get_val(sp, "Mapping"); + if (val == NULL) { + /* no map */ + lu->maxmap = 0; + } else { + lu->maxmap = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "Mapping", i, 0); + if (val == NULL) + break; + if (lu->maxmap >= MAX_LU_MAP) { + ISTGT_ERRLOG("LU%d: too many mapping\n", lu->num); + goto error_return; + } + pg_tag = istgt_get_nmval(sp, "Mapping", i, 0); + ig_tag = istgt_get_nmval(sp, "Mapping", i, 1); + if (pg_tag == NULL || ig_tag == NULL) { + ISTGT_ERRLOG("LU%d: mapping error\n", lu->num); + goto error_return; + } + if (strncasecmp(pg_tag, "PortalGroup", + strlen("PortalGroup")) != 0 + || sscanf(pg_tag, "%*[^0-9]%d", &pg_tag_i) != 1) { + ISTGT_ERRLOG("LU%d: mapping portal error\n", lu->num); + goto error_return; + } + if (strncasecmp(ig_tag, "InitiatorGroup", + strlen("InitiatorGroup")) != 0 + || sscanf(ig_tag, "%*[^0-9]%d", &ig_tag_i) != 1) { + ISTGT_ERRLOG("LU%d: mapping initiator error\n", lu->num); + goto error_return; + } + if (pg_tag_i < 1 || ig_tag_i < 1) { + ISTGT_ERRLOG("LU%d: invalid group tag\n", lu->num); + goto error_return; + } + MTX_LOCK(&istgt->mutex); + pgp = istgt_lu_find_portalgroup(istgt, pg_tag_i); + if (pgp == NULL) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("LU%d: PortalGroup%d not found\n", + lu->num, pg_tag_i); + goto error_return; + } + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag_i); + if (igp == NULL) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("LU%d: InitiatorGroup%d not found\n", + lu->num, ig_tag_i); + goto error_return; + } + pgp->ref++; + igp->ref++; + MTX_UNLOCK(&istgt->mutex); + lu->map[i].pg_tag = pg_tag_i; + lu->map[i].pg_aas = AAS_ACTIVE_OPTIMIZED; + //lu->map[i].pg_aas = AAS_ACTIVE_NON_OPTIMIZED; + lu->map[i].pg_aas |= AAS_STATUS_IMPLICIT; + lu->map[i].ig_tag = ig_tag_i; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Mapping PortalGroup%d InitiatorGroup%d\n", + lu->map[i].pg_tag, lu->map[i].ig_tag); + lu->maxmap = i + 1; + } + } + if (lu->maxmap == 0) { + ISTGT_ERRLOG("LU%d: no Mapping\n", lu->num); + goto error_return; + } + + val = istgt_get_val(sp, "AuthMethod"); + if (val == NULL) { + /* none */ + lu->no_auth_chap = 0; + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else { + lu->no_auth_chap = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "AuthMethod", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "CHAP") == 0) { + lu->auth_chap = 1; + } else if (strcasecmp(val, "Mutual") == 0) { + lu->auth_chap_mutual = 1; + } else if (strcasecmp(val, "Auto") == 0) { + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else if (strcasecmp(val, "None") == 0) { + lu->no_auth_chap = 1; + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else { + ISTGT_ERRLOG("LU%d: unknown auth\n", lu->num); + goto error_return; + } + } + if (lu->auth_chap_mutual && !lu->auth_chap) { + ISTGT_ERRLOG("LU%d: Mutual but not CHAP\n", lu->num); + goto error_return; + } + } + if (lu->no_auth_chap != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n"); + } else if (lu->auth_chap == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n", + lu->auth_chap ? "CHAP" : "", + lu->auth_chap_mutual ? "Mutual" : ""); + } + + val = istgt_get_val(sp, "AuthGroup"); + if (val == NULL) { + lu->auth_group = 0; + } else { + ag_tag = val; + if (strcasecmp(ag_tag, "None") == 0) { + ag_tag_i = 0; + } else { + if (strncasecmp(ag_tag, "AuthGroup", + strlen("AuthGroup")) != 0 + || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) { + ISTGT_ERRLOG("LU%d: auth group error\n", lu->num); + goto error_return; + } + if (ag_tag_i == 0) { + ISTGT_ERRLOG("LU%d: invalid auth group %d\n", lu->num, + ag_tag_i); + goto error_return; + } + } + lu->auth_group = ag_tag_i; + } + if (lu->auth_group == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup None\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup AuthGroup%d\n", + lu->auth_group); + } + + val = istgt_get_val(sp, "UseDigest"); + if (val != NULL) { + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "UseDigest", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "Header") == 0) { + lu->header_digest = 1; + } else if (strcasecmp(val, "Data") == 0) { + lu->data_digest = 1; + } else if (strcasecmp(val, "Auto") == 0) { + lu->header_digest = 0; + lu->data_digest = 0; + } else { + ISTGT_ERRLOG("LU%d: unknown digest\n", lu->num); + goto error_return; + } + } + } + if (lu->header_digest == 0 && lu->data_digest == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest Auto\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest %s %s\n", + lu->header_digest ? "Header" : "", + lu->data_digest ? "Data" : ""); + } + + val = istgt_get_val(sp, "ReadOnly"); + if (val == NULL) { + lu->readonly = 0; + } else if (strcasecmp(val, "No") == 0){ + lu->readonly = 0; + } else if (strcasecmp(val, "Yes") == 0) { + lu->readonly = 1; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ReadOnly %s\n", + lu->readonly ? "Yes" : "No"); + + val = istgt_get_val(sp, "UnitType"); + if (val == NULL) { + ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num); + goto error_return; + } + if (strcasecmp(val, "Pass") == 0) { + lu->type = ISTGT_LU_TYPE_PASS; + } else if (strcasecmp(val, "Disk") == 0) { + lu->type = ISTGT_LU_TYPE_DISK; + } else if (strcasecmp(val, "DVD") == 0) { + lu->type = ISTGT_LU_TYPE_DVD; + } else if (strcasecmp(val, "Tape") == 0) { + lu->type = ISTGT_LU_TYPE_TAPE; + } else { + ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num); + goto error_return; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitType %d (%s)\n", + lu->type, val); + + val = istgt_get_val(sp, "UnitOnline"); + if (val == NULL) { + lu->online = 1; + } else if (strcasecmp(val, "Yes") == 0) { + lu->online = 1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitOnline %s\n", + lu->online ? "Yes" : "No"); + + vendor = istgt_get_nmval(sp, "UnitInquiry", 0, 0); + product = istgt_get_nmval(sp, "UnitInquiry", 0, 1); + revision = istgt_get_nmval(sp, "UnitInquiry", 0, 2); + serial = istgt_get_nmval(sp, "UnitInquiry", 0, 3); + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + if (vendor == NULL || strlen(vendor) == 0) + vendor = DEFAULT_LU_VENDOR_DISK; + if (product == NULL || strlen(product) == 0) + product = DEFAULT_LU_PRODUCT_DISK; + if (revision == NULL || strlen(revision) == 0) + revision = DEFAULT_LU_REVISION_DISK; + if (serial == NULL || strlen(serial) == 0) { + snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num); + serial = (const char *) &buf[0]; + } + break; + case ISTGT_LU_TYPE_DVD: + if (vendor == NULL || strlen(vendor) == 0) + vendor = DEFAULT_LU_VENDOR_DVD; + if (product == NULL || strlen(product) == 0) + product = DEFAULT_LU_PRODUCT_DVD; + if (revision == NULL || strlen(revision) == 0) + revision = DEFAULT_LU_REVISION_DVD; + if (serial == NULL || strlen(serial) == 0) { + snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num); + serial = (const char *) &buf[0]; + } + break; + case ISTGT_LU_TYPE_TAPE: + if (vendor == NULL || strlen(vendor) == 0) + vendor = DEFAULT_LU_VENDOR_TAPE; + if (product == NULL || strlen(product) == 0) + product = DEFAULT_LU_PRODUCT_TAPE; + if (revision == NULL || strlen(revision) == 0) + revision = DEFAULT_LU_REVISION_TAPE; + if (serial == NULL || strlen(serial) == 0) { +#ifdef USE_LU_TAPE_DLT8000 + snprintf(buf, sizeof buf, "CX%.8d", 10000000 + nbs + lu->num); +#else + snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num); +#endif /* USE_LU_TAPE_DLT8000 */ + serial = (const char *) &buf[0]; + } + break; + default: + if (vendor == NULL || strlen(vendor) == 0) + vendor = DEFAULT_LU_VENDOR; + if (product == NULL || strlen(product) == 0) + product = DEFAULT_LU_PRODUCT; + if (revision == NULL || strlen(revision) == 0) + revision = DEFAULT_LU_REVISION; + if (serial == NULL || strlen(serial) == 0) { + snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num); + serial = (const char *) &buf[0]; + } + break; + } + lu->inq_vendor = xstrdup(vendor); + lu->inq_product = xstrdup(product); + lu->inq_revision = xstrdup(revision); + lu->inq_serial = xstrdup(serial); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitInquiry %s %s %s %s\n", + lu->inq_vendor, lu->inq_product, lu->inq_revision, + lu->inq_serial); + + val = istgt_get_val(sp, "BlockLength"); + if (val == NULL) { + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + lu->blocklen = DEFAULT_LU_BLOCKLEN_DISK; + break; + case ISTGT_LU_TYPE_DVD: + lu->blocklen = DEFAULT_LU_BLOCKLEN_DVD; + break; + case ISTGT_LU_TYPE_TAPE: + lu->blocklen = DEFAULT_LU_BLOCKLEN_TAPE; + break; + default: + lu->blocklen = DEFAULT_LU_BLOCKLEN; + break; + } + } else { + lu->blocklen = (int) strtol(val, NULL, 10); + } + + lu->rshift = 0; + lu->recordsize = lu->blocklen; //old volumes + val = istgt_get_val(sp, "PhysRecordLength"); + if (val != NULL) { + int lbPerRecord, lrsize; + lrsize = (int) strtol(val, NULL, 10); + if (lrsize > lu->blocklen && lrsize < 131073) { + lbPerRecord = lrsize / lu->blocklen; + if (lbPerRecord & (lbPerRecord-1)) { + ISTGT_ERRLOG("LU%d: ignore invalid recordsize:%u blocklen:%u\n", + lu->num, lrsize, lu->blocklen); + } else { + lu->recordsize = lrsize; + lu->rshift = fls(lbPerRecord) - 1; + } + } + } + + val = istgt_get_val(sp, "QueueDepth"); + if (val == NULL) { + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + lu->queue_depth = DEFAULT_LU_QUEUE_DEPTH; + //lu->queue_depth = 0; + break; + case ISTGT_LU_TYPE_DVD: + case ISTGT_LU_TYPE_TAPE: + default: + lu->queue_depth = 0; + break; + } + } else { + lu->queue_depth = (int) strtol(val, NULL, 10); + } + if (lu->queue_depth < 0 || lu->queue_depth >= MAX_LU_QUEUE_DEPTH) { + ISTGT_ERRLOG("LU%d: queue depth %d is not in range, resetting to %d\n", lu->num, lu->queue_depth, DEFAULT_LU_QUEUE_DEPTH); + lu->queue_depth = DEFAULT_LU_QUEUE_DEPTH; + goto error_return; + } + + lu->luworkers = 0; + lu->luworkersActive = 0; + lu->conns = 0; + lu->limit_q_size = 0; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "BlockLength %d, PhysRecordLength %d, QueueDepth %d\n", + lu->blocklen, lu->recordsize, lu->queue_depth); + + val = istgt_get_val(sp, "Luworkers"); + if (val == NULL) { + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + lu->luworkers = g_num_luworkers; + break; + case ISTGT_LU_TYPE_DVD: + case ISTGT_LU_TYPE_TAPE: + default: + lu->luworkers = 0; + break; + } + } else { + lu->luworkers = (int) strtol(val, NULL, 10); + if (lu->luworkers > (ISTGT_MAX_NUM_LUWORKERS - 1)) + lu->luworkers = (ISTGT_MAX_NUM_LUWORKERS - 1); + else if (lu->luworkers < 1) + lu->luworkers = 1; + } + + lu->maxlun = 0; + for (i = 0; i < MAX_LU_LUN; i++) { + lu->lun[i].type = ISTGT_LU_LUN_TYPE_NONE; + lu->lun[i].rotationrate = DEFAULT_LU_ROTATIONRATE; + lu->lun[i].formfactor = DEFAULT_LU_FORMFACTOR; + lu->lun[i].readcache = 1; + lu->lun[i].writecache = 1; + lu->lun[i].unmap = 0; + lu->lun[i].wzero = 0; + lu->lun[i].ats = 0; + lu->lun[i].xcopy = 0; + lu->lun[i].wsame = 0; + lu->lun[i].dpofua = 0; + lu->lun[i].serial = NULL; + lu->lun[i].spec = NULL; + lu->lun[i].opt_tlen = 1; + snprintf(buf, sizeof buf, "LUN%d", i); + val = istgt_get_val(sp, buf); + if (val == NULL) + continue; + if (i != 0) { + /* default LUN serial (except LUN0) */ + snprintf(buf2, sizeof buf2, "%sL%d", lu->inq_serial, i); + lu->lun[i].serial = xstrdup(buf2); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Serial %s (default)\n", + i, buf2); + } + for (j = 0; ; j++) { + val = istgt_get_nmval(sp, buf, j, 0); + if (val == NULL) + break; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d\n", i); + if (strcasecmp(val, "Device") == 0) { + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i); + goto error_return; + } + lu->lun[i].type = ISTGT_LU_LUN_TYPE_DEVICE; + + file = istgt_get_nmval(sp, buf, j, 1); + if (file == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + lu->lun[i].u.device.file = xstrdup(file); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Device file=%s\n", + lu->lun[i].u.device.file); + } else if (strcasecmp(val, "Storage") == 0) { + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i); + goto error_return; + } + lu->lun[i].type = ISTGT_LU_LUN_TYPE_STORAGE; + + file = istgt_get_nmval(sp, buf, j, 1); + size = istgt_get_nmval(sp, buf, j, 2); + rsz = istgt_get_nmval(sp, buf, j, 3); + if (file == NULL || size == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + if (rsz == NULL) { + lu->lun[i].u.storage.rsize = 0; + } else { + uint64_t vall; + char *endp, *p; + vall = (uint64_t) strtoul(rsz, &endp, 10); + //error will mean vall == ULONG_MAX + if (endp != NULL) { + p = endp; + switch (toupper((int) *p)) { + case 'Z': vall *= (uint64_t) 1024ULL; + case 'E': vall *= (uint64_t) 1024ULL; + case 'P': vall *= (uint64_t) 1024ULL; + case 'T': vall *= (uint64_t) 1024ULL; + case 'G': vall *= (uint64_t) 1024ULL; + case 'M': vall *= (uint64_t) 1024ULL; + case 'K': vall *= (uint64_t) 1024ULL; + break; + } + } + if (vall > 131072) + lu->lun[i].u.storage.rsize = 131072; + else + lu->lun[i].u.storage.rsize = (uint32_t)vall; + } + if ((strcasecmp(size, "Auto") == 0 + || strcasecmp(size, "Size") == 0) && istgt->OperationalMode == 0) { + lu->lun[i].u.storage.size = istgt_lu_get_filesize(file); + } else { + lu->lun[i].u.storage.size = istgt_lu_parse_size(size); + } + if (lu->lun[i].u.storage.size == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: Auto size error (%s)\n", lu->num, i, file); + goto error_return; + } + lu->lun[i].u.storage.fd = -1; + lu->lun[i].u.storage.file = xstrdup(file); + gotstorage = 1; + } else if (strcasecmp(val, "Removable") == 0) { + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i); + goto error_return; + } + lu->lun[i].type = ISTGT_LU_LUN_TYPE_REMOVABLE; + + flags = istgt_get_nmval(sp, buf, j, 1); + file = istgt_get_nmval(sp, buf, j, 2); + size = istgt_get_nmval(sp, buf, j, 3); + if (flags == NULL || file == NULL || size == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + mflags = istgt_lu_parse_media_flags(flags); + msize = istgt_lu_parse_media_size(file, size, &mflags); + if (msize == 0 && strcasecmp(file, "/dev/null") == 0) { + /* empty media */ + } else if (msize == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + lu->lun[i].u.removable.type = 0; + lu->lun[i].u.removable.id = 0; + lu->lun[i].u.removable.fd = -1; + lu->lun[i].u.removable.flags = mflags; + lu->lun[i].u.removable.file = xstrdup(file); + lu->lun[i].u.removable.size = msize; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Removable file=%s, size=%"PRIu64", flags=%x\n", + lu->lun[i].u.removable.file, + lu->lun[i].u.removable.size, + lu->lun[i].u.removable.flags); + } else if (strncasecmp(val, "Slot", 4) == 0) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + lu->lun[i].u.slot.maxslot = 0; + for (k = 0; k < MAX_LU_LUN_SLOT; k++) { + lu->lun[i].u.slot.present[k] = 0; + lu->lun[i].u.slot.flags[k] = 0; + lu->lun[i].u.slot.file[k] = NULL; + lu->lun[i].u.slot.size[k] = 0; + } + } else if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_SLOT) { + ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i); + goto error_return; + } + lu->lun[i].type = ISTGT_LU_LUN_TYPE_SLOT; + if (sscanf(val, "%*[^0-9]%d", &slot) != 1) { + ISTGT_ERRLOG("LU%d: slot number error\n", lu->num); + goto error_return; + } + if (slot < 0 || slot >= MAX_LU_LUN_SLOT) { + ISTGT_ERRLOG("LU%d: slot number range error\n", lu->num); + goto error_return; + } + if (lu->lun[i].u.slot.present[slot]) { + ISTGT_ERRLOG("LU%d: duplicate slot %d\n", lu->num, slot); + goto error_return; + } + lu->lun[i].u.slot.present[slot] = 1; + if (slot + 1 > lu->lun[i].u.slot.maxslot) { + lu->lun[i].u.slot.maxslot = slot + 1; + } + + flags = istgt_get_nmval(sp, buf, j, 1); + file = istgt_get_nmval(sp, buf, j, 2); + size = istgt_get_nmval(sp, buf, j, 3); + if (flags == NULL || file == NULL || size == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + mflags = istgt_lu_parse_media_flags(flags); + msize = istgt_lu_parse_media_size(file, size, &mflags); + if (msize == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + lu->lun[i].u.slot.flags[slot] = mflags; + lu->lun[i].u.slot.file[slot] = xstrdup(file); + lu->lun[i].u.slot.size[slot] = msize; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "Slot%d file=%s, size=%"PRIu64", flags=%x\n", + slot, + lu->lun[i].u.slot.file[slot], + lu->lun[i].u.slot.size[slot], + lu->lun[i].u.slot.flags[slot]); + } else if (strncasecmp(val, "Option", 6) == 0) { + key = istgt_get_nmval(sp, buf, j, 1); + val = istgt_get_nmval(sp, buf, j, 2); + if (key == NULL || val == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + if (strcasecmp(key, "Serial") == 0) { + /* set LUN serial */ + if (strlen(val) == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: no serial\n", + lu->num, i); + goto error_return; + } + xfree(lu->lun[i].serial); + lu->lun[i].serial = xstrdup(val); + } else if (strcasecmp(key, "RPM") == 0) { + rpm = (int)strtol(val, NULL, 10); + if (rpm < 0) { + rpm = 0; + } else if (rpm > 0xfffe) { + rpm = 0xfffe; + } + /* 0 not reported, 1 SSD, 5400/7200/10000/15000 - rotation rate(rpm) */ + lu->lun[i].rotationrate = rpm; + } else if (strcasecmp(key, "FormFactor") == 0) { + formfactor = (int)strtol(val, NULL, 10); + if (formfactor < 0) { + formfactor = 0; + } else if (formfactor > 0x0f) { + formfactor = 0xf; + } + lu->lun[i].formfactor = formfactor; + } else if (strcasecmp(key, "ReadCache") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].readcache = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].readcache = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "WriteCache") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].writecache = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].writecache = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "Unmap") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].unmap = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].unmap = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "WZero") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (lu->lun[i].unmap == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: Wzero enabled while Unmap disabled\n", lu->num, i); + goto error_return; + } + lu->lun[i].wzero = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].wzero = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "ats") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].ats = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].ats = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "xcopy") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].xcopy = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].xcopy = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "wsame") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].wsame = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].wsame = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "dpofua") == 0) { + if (strcasecmp(val, "Enable") == 0) { + lu->lun[i].dpofua = 1; + } else if (strcasecmp(val, "Disable") == 0) { + lu->lun[i].dpofua = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "OptTlen") == 0) { + opt_tlen = (int)strtol(val, NULL, 10); + if (opt_tlen < 0) { + opt_tlen = 0; + } else if (opt_tlen > 0xffff) { + opt_tlen = 0xffff; + } + lu->lun[i].opt_tlen = opt_tlen; + ISTGT_ERRLOG("LU%d: LUN%d: opt_transfer_len (%d)\n", + lu->num, i, opt_tlen); + } else { + ISTGT_WARNLOG("LU%d: LUN%d: unknown key(%s)\n", + lu->num, i, key); + continue; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Option %s => %s\n", + i, key, val); + continue; + } else { + ISTGT_ERRLOG("LU%d: unknown lun type\n", lu->num); + goto error_return; + } + } + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_SLOT) { + if (lu->lun[i].u.slot.maxslot == 0) { + ISTGT_ERRLOG("LU%d: no slot\n", lu->num); + goto error_return; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "maxslot=%d\n", + lu->lun[i].u.slot.maxslot); + } + if (gotstorage == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "Lu%d: LUN%d: ADD Storage:%s, size=%lu rsz:%u que:%d rpm:%d %s%s%s%s%s%s%s\n", + lu->num, i, lu->lun[i].u.storage.file, lu->lun[i].u.storage.size, + lu->lun[i].u.storage.rsize, lu->queue_depth, lu->lun[i].rotationrate, + lu->lun[i].readcache ? "" : "RCD", + lu->lun[i].writecache ? " WCE" : "", + lu->lun[i].ats ? " ATS" : "", + lu->lun[i].unmap ? " UNMAP" : "", + lu->lun[i].wsame ? " WSAME" : "", + lu->lun[i].dpofua ? " DPOFUA" : "", + lu->lun[i].wzero ? " WZERO" : ""); + + gotstorage = 0; + } + lu->maxlun = i + 1; + } + if (lu->maxlun == 0) { + ISTGT_ERRLOG("LU%d: no LUN\n", lu->num); + goto error_return; + } + if (lu->lun[0].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_ERRLOG("LU%d: no LUN0\n", lu->num); + goto error_return; + } + + /* set local values if any */ + rc = istgt_lu_set_local_settings(istgt, sp, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: local setting error\n", lu->num); + goto error_return; + } + + /* tsih 0 is reserved */ + for (i = 0; i < MAX_LU_TSIH; i++) { + lu->tsih[i].tag = 0; + lu->tsih[i].tsih = 0; + lu->tsih[i].initiator_port = NULL; + } + lu->maxtsih = 1; + lu->last_tsih = 0; + + MTX_LOCK(&istgt->mutex); + istgt->nlogical_unit++; + istgt->logical_unit[lu->num] = lu; + MTX_UNLOCK(&istgt->mutex); + return 0; + + error_return: + xfree(lu->name); + xfree(lu->alias); + xfree(lu->inq_vendor); + xfree(lu->inq_product); + xfree(lu->inq_revision); + for (i = 0; i < MAX_LU_LUN; i++) { + switch (lu->lun[i].type) { + case ISTGT_LU_LUN_TYPE_DEVICE: + xfree(lu->lun[i].u.device.file); + break; + case ISTGT_LU_LUN_TYPE_STORAGE: + xfree(lu->lun[i].u.storage.file); + break; + case ISTGT_LU_LUN_TYPE_REMOVABLE: + xfree(lu->lun[i].u.removable.file); + break; + case ISTGT_LU_LUN_TYPE_SLOT: + for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) { + xfree(lu->lun[i].u.slot.file[j]); + } + break; + case ISTGT_LU_LUN_TYPE_NONE: + default: + break; + } + } + for (i = 0; i < MAX_LU_TSIH; i++) { + xfree(lu->tsih[i].initiator_port); + } + for (i = 0; i < lu->maxmap; i++) { + pg_tag_i = lu->map[i].pg_tag; + ig_tag_i = lu->map[i].ig_tag; + MTX_LOCK(&istgt->mutex); + pgp = istgt_lu_find_portalgroup(istgt, pg_tag_i); + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag_i); + if (pgp != NULL && igp != NULL) { + pgp->ref--; + igp->ref--; + } + MTX_UNLOCK(&istgt->mutex); + } + + xfree(lu); + return -1; +} + +static int +istgt_lu_close_connection(ISTGT_LU_Ptr lu, INITIATOR_GROUP *igp_new) +{ + CONN_Ptr conn; + int i,j,found; + + if (igp_new == NULL){ + return -1; + } + for(i = 0; i < igp_new->ninitiators; i++) { + if (strcasecmp(igp_new->initiators[i], "ALL") == 0) + return 0; + } + /* Traverse all connections to Disconnect the invalid ones */ + for (j = 1; j < MAX_LU_TSIH; j++) { + if (lu->tsih[j].initiator_port != NULL + && lu->tsih[j].tsih != 0) { + found = 0; + conn = istgt_find_conn(lu->tsih[j].initiator_port, lu->name, lu->tsih[j].tsih); + if (conn == NULL) + continue; + for(i = 0; i < igp_new->ninitiators; i++) { + if (igp_new->initiators[i] == NULL) + continue; + if (strcasecmp(igp_new->initiators[i], conn->initiator_name) == 0) { + found = 1; + break; + } + } + if (!found) { + ISTGT_NOTICELOG("Close all connections for the Initiator %s\n", conn->initiator_name); + MTX_UNLOCK(&conn->istgt->mutex); + istgt_iscsi_send_async(conn); + MTX_LOCK(&conn->istgt->mutex); + } + } + } + + return 0; +} + +extern clockid_t clockid; +static int +istgt_lu_update_unit(ISTGT_LU_Ptr lu, CF_SECTION *sp) +{ + char buf[MAX_TMPBUF]; + INITIATOR_GROUP *igp_old, *igp_new; + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + const char *ig_tag_new; + const char *ag_tag; + const char *file, *size, *rsz; + const char *val, *key; + int ig_tag_i_new; + int ag_tag_i; + int i, j; + int rc, flags; + uint64_t old_size=0, new_size; + uint32_t old_rsize=0, new_rsize; + int rpm, formfactor, opt_tlen; + int storagechange=0; + + val = istgt_get_val(sp, "Mapping"); + if (val == NULL) { + /* no map */ + lu->maxmap = 0; + } else { + lu->maxmap = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "Mapping", i, 0); + if (val == NULL) + break; + if (lu->maxmap >= MAX_LU_MAP) { + ISTGT_ERRLOG("LU%d: too many mapping\n", lu->num); + goto error_return; + } + ig_tag_new = istgt_get_nmval(sp, "Mapping", i, 1); + if (ig_tag_new == NULL) { + ISTGT_ERRLOG("LU%d: mapping error\n", lu->num); + goto error_return; + } + if (strncasecmp(ig_tag_new, "InitiatorGroup", + strlen("InitiatorGroup")) != 0 + || sscanf(ig_tag_new, "%*[^0-9]%d", &ig_tag_i_new) != 1) { + ISTGT_ERRLOG("LU%d: mapping initiator error\n", lu->num); + goto error_return; + } + if (ig_tag_i_new < 1) { + ISTGT_ERRLOG("LU%d: invalid group tag\n", lu->num); + goto error_return; + } + MTX_LOCK(&lu->istgt->mutex); + igp_new = istgt_lu_find_initiatorgroup(lu->istgt, ig_tag_i_new); + if (igp_new == NULL) { + MTX_UNLOCK(&lu->istgt->mutex); + ISTGT_ERRLOG("LU%d: InitiatorGroup%d not found\n", + lu->num, ig_tag_i_new); + goto error_return; + } + igp_new->ref++; + igp_old = istgt_lu_find_initiatorgroup(lu->istgt, lu->map[i].ig_tag); + if (igp_old == NULL) { + ISTGT_NOTICELOG("LU%d: InitiatoGroup%d not found\n", + lu->num,lu->map[i].ig_tag ); + } + ISTGT_NOTICELOG("initiator grp updated with new value %d\n", igp_new->tag); + rc = istgt_lu_close_connection(lu, igp_new); + MTX_UNLOCK(&lu->istgt->mutex); + if (rc < 0){ + /* handle the error */ + ISTGT_ERRLOG("Unable to close Unauthorised connections for LU%d\n",lu->num); + goto error_out; + } + lu->map[i].ig_tag = ig_tag_i_new; + lu->maxmap = i + 1; + + + } + } + if (lu->maxmap == 0) { + ISTGT_ERRLOG("LU%d: no Mapping\n", lu->num); + goto error_return; + } + + val = istgt_get_val(sp, "AuthMethod"); + if (val == NULL) { + /* none */ + lu->no_auth_chap = 0; + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else { + lu->no_auth_chap = 0; + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "AuthMethod", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "CHAP") == 0) { + lu->auth_chap = 1; + } else if (strcasecmp(val, "Mutual") == 0) { + lu->auth_chap_mutual = 1; + } else if (strcasecmp(val, "Auto") == 0) { + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else if (strcasecmp(val, "None") == 0) { + lu->no_auth_chap = 1; + lu->auth_chap = 0; + lu->auth_chap_mutual = 0; + } else { + ISTGT_ERRLOG("LU%d: unknown auth\n", lu->num); + goto error_return; + } + } + if (lu->auth_chap_mutual && !lu->auth_chap) { + ISTGT_ERRLOG("LU%d: Mutual but not CHAP\n", lu->num); + goto error_return; + } + } + if (lu->no_auth_chap != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n"); + } else if (lu->auth_chap == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n", + lu->auth_chap ? "CHAP" : "", + lu->auth_chap_mutual ? "Mutual" : ""); + } + + val = istgt_get_val(sp, "AuthGroup"); + if (val == NULL) { + lu->auth_group = 0; + } else { + ag_tag = val; + if (strcasecmp(ag_tag, "None") == 0) { + ag_tag_i = 0; + } else { + if (strncasecmp(ag_tag, "AuthGroup", + strlen("AuthGroup")) != 0 + || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) { + ISTGT_ERRLOG("LU%d: auth group error\n", lu->num); + goto error_return; + } + if (ag_tag_i == 0) { + ISTGT_ERRLOG("LU%d: invalid auth group %d\n", lu->num, + ag_tag_i); + goto error_return; + } + } + lu->auth_group = ag_tag_i; + } + if (lu->auth_group == 0) { + ISTGT_NOTICELOG("AuthGroup None\n"); + } else { + ISTGT_NOTICELOG("AuthGroup AuthGroup%d\n", + lu->auth_group); + } + + val = istgt_get_val(sp, "UnitOnline"); + if (val == NULL) { + lu->online = 1; + } else if (strcasecmp(val, "Yes") == 0) { + lu->online = 1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitOnline %s\n", + lu->online ? "Yes" : "No"); + val = istgt_get_val(sp, "ReadOnly"); + if (val == NULL) { + lu->readonly = 0; + } else if (strcasecmp(val, "No") == 0) { + lu->readonly = 0; + } else if (strcasecmp(val, "Yes") == 0) { + lu->readonly = 1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ReadOnly %s\n", + lu->readonly ? "Yes" : "No"); + + for (i = 0; i < MAX_LU_LUN; i++) { + snprintf(buf, sizeof buf, "LUN%d", i); + val = istgt_get_val(sp, buf); + if (val == NULL) + continue; + if(lu->lun[i].spec == NULL) + continue; + spec = lu->lun[i].spec; + storagechange = 0; + for (j = 0; ; j++) { + val = istgt_get_nmval(sp, buf, j, 0); + if (val == NULL) + break; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d\n", i); + if (strcasecmp(val, "Device") == 0) { + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i); + goto error_return; + } + lu->lun[i].type = ISTGT_LU_LUN_TYPE_DEVICE; + + file = istgt_get_nmval(sp, buf, j, 1); + if (file == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + lu->lun[i].u.device.file = xstrdup(file); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Device file=%s\n", + lu->lun[i].u.device.file); + } else if (strcasecmp(val, "Storage") == 0) { + file = istgt_get_nmval(sp, buf, j, 1); + size = istgt_get_nmval(sp, buf, j, 2); + rsz = istgt_get_nmval(sp, buf, j, 3); + if (file == NULL || size == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + old_rsize = lu->lun[i].u.storage.rsize; + old_size = lu->lun[i].u.storage.size; + if ((strcasecmp(size, "Auto") == 0 + || strcasecmp(size, "Size") == 0) + && lu->istgt->OperationalMode == 0) { + new_size = istgt_lu_get_filesize(file); + } else { + new_size = istgt_lu_parse_size(size); + } + new_rsize = 0; + if (rsz != NULL) { + uint64_t vall; + char *endp, *p; + vall = (uint64_t) strtoul(rsz, &endp, 10); + //error will mean vall == ULONG_MAX + if (endp != NULL) { + p = endp; + switch (toupper((int) *p)) { + case 'Z': vall *= (uint64_t) 1024ULL; + case 'E': vall *= (uint64_t) 1024ULL; + case 'P': vall *= (uint64_t) 1024ULL; + case 'T': vall *= (uint64_t) 1024ULL; + case 'G': vall *= (uint64_t) 1024ULL; + case 'M': vall *= (uint64_t) 1024ULL; + case 'K': vall *= (uint64_t) 1024ULL; + break; + } + } + if (vall > 131072) + new_rsize = 131072; + else + new_rsize = (uint32_t)vall; + } + + if (old_size == new_size && new_rsize == old_rsize + && spec != NULL && strcasecmp(file, spec->file) == 0) + continue; + + lu->lun[i].u.storage.size = new_size; + lu->lun[i].u.storage.rsize = new_rsize; + + if (lu->lun[i].u.storage.size == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: Auto size error (%s)\n", lu->num, i, file); + goto error_return; + } + if (lu->lun[i].u.storage.file) + xfree(lu->lun[i].u.storage.file); + lu->lun[i].u.storage.file = xstrdup(file); + ++storagechange; + } else if (strncasecmp(val, "Option", 6) == 0) { + key = istgt_get_nmval(sp, buf, j, 1); + val = istgt_get_nmval(sp, buf, j, 2); + if (key == NULL || val == NULL) { + ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i); + goto error_return; + } + if (strcasecmp(key, "Serial") == 0) { + /* set LUN serial */ + if (strlen(val) == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: no serial\n", + lu->num, i); + goto error_return; + } + if (!lu->lun[i].serial || + (strcasecmp(lu->lun[i].serial, val) != 0)) { + ++storagechange; + xfree(lu->lun[i].serial); + lu->lun[i].serial = xstrdup(val); + } + } else if (strcasecmp(key, "RPM") == 0) { + rpm = (int)strtol(val, NULL, 10); + if (rpm < 0) { + rpm = 0; + } else if (rpm > 0xfffe) { + rpm = 0xfffe; + } + if (lu->lun[i].rotationrate != rpm) + ++storagechange; + lu->lun[i].rotationrate = rpm; + } else if (strcasecmp(key, "FormFactor") == 0) { + formfactor = (int)strtol(val, NULL, 10); + if (formfactor < 0) { + formfactor = 0; + } else if (formfactor > 0x0f) { + formfactor = 0xf; + } + if (lu->lun[i].formfactor != formfactor) + ++storagechange; + lu->lun[i].formfactor = formfactor; + } else if (strcasecmp(key, "ReadCache") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->readcache) + ++storagechange; + lu->lun[i].readcache = 1; + spec->readcache = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->readcache) + ++storagechange; + lu->lun[i].readcache = 0; + spec->readcache = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "WriteCache") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->writecache) + ++storagechange; + lu->lun[i].writecache = 1; + spec->writecache = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->writecache) + ++storagechange; + lu->lun[i].writecache = 0; + spec->writecache = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "Unmap") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->unmap) + ++storagechange; + lu->lun[i].unmap = 1; + spec->unmap = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->unmap) + ++storagechange; + lu->lun[i].unmap = 0; + spec->unmap = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "WZero") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->wzero) + ++storagechange; + lu->lun[i].wzero = 1; + spec->wzero = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->wzero) + ++storagechange; + lu->lun[i].wzero = 0; + spec->wzero = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "ats") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->ats) + ++storagechange; + lu->lun[i].ats = 1; + spec->ats = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->ats) + ++storagechange; + lu->lun[i].ats = 0; + spec->ats = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "xcopy") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->xcopy) + ++storagechange; + lu->lun[i].xcopy = 1; + spec->xcopy = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->xcopy) + ++storagechange; + lu->lun[i].xcopy = 0; + spec->xcopy = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "wsame") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->wsame) + ++storagechange; + lu->lun[i].wsame = 1; + spec->wsame = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->wsame) + ++storagechange; + lu->lun[i].wsame = 0; + spec->wsame = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "dpofua") == 0) { + if (strcasecmp(val, "Enable") == 0) { + if (!spec->dpofua) + ++storagechange; + lu->lun[i].dpofua = 1; + spec->dpofua = 1; + } else if (strcasecmp(val, "Disable") == 0) { + if (spec->dpofua) + ++storagechange; + lu->lun[i].dpofua = 0; + spec->dpofua = 0; + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n", + lu->num, i, val); + } + } else if (strcasecmp(key, "OptTlen") == 0) { + opt_tlen = (int)strtol(val, NULL, 10); + if (opt_tlen < 0) { + opt_tlen = 0; + } else if (opt_tlen > 0xffff) { + opt_tlen = 0xffff; + } + lu->lun[i].opt_tlen = opt_tlen; + ISTGT_ERRLOG("LU%d: LUN%d: opt_transfer_len (%d)\n", + lu->num, i, opt_tlen); + } else { + ISTGT_WARNLOG("LU%d: LUN%d: unknown key(%s)\n", + lu->num, i, key); + continue; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Option %s => %s\n", + i, key, val); + continue; + } else { + ISTGT_ERRLOG("LU%d: unknown lun type\n", lu->num); + //goto error_return; + } + } + /* update the quota */ + if ((storagechange != 0) && (lu->lun[i].type == ISTGT_LU_LUN_TYPE_STORAGE)) { + ISTGT_NOTICELOG("LU%d: LUN%d: UPD Storage:%s, size=%lu rsz=%u rpm:%d %s%s%s%s%s%s%s%s\n", + lu->num, i, lu->lun[i].u.storage.file, lu->lun[i].u.storage.size, + lu->lun[i].u.storage.rsize, lu->lun[i].rotationrate, + lu->lun[i].readcache ? "" : "RCD", + lu->lun[i].writecache ? " WCE" : "", + lu->lun[i].ats ? " ATS" : "", + lu->lun[i].ats ? " XCOPY" : "", + lu->lun[i].unmap ? " UNMAP" : "", + lu->lun[i].wsame ? " WSAME" : "", + lu->lun[i].dpofua ? " DPOFUA" : "", + lu->lun[i].wzero ? " WZERO" : "" + ); + if(lu->istgt->OperationalMode) { + clock_gettime(clockid, &spec->close_started); + rc = istgt_lu_disk_close(lu, i); + } else { + clock_gettime(clockid, &spec->open_started); + rc = istgt_lu_disk_open(lu, i); + } + if (rc < 0 && !lu->istgt->OperationalMode) { + ISTGT_ERRLOG("logical unit update error, retry with old values (size:%lu rsize:%u)\n", old_size, old_rsize); + lu->lun[i].u.storage.size = old_size; + lu->lun[i].u.storage.rsize = old_rsize; + flags = lu->readonly ? O_RDONLY : O_RDWR; + rc = spec->open(spec, flags, 0666); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d)\n", + lu->num, i, errno); + goto error_return; + } + } + if (rc >= 0) { + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + nexus->ua_pending |= ISTGT_UA_LUN_CHANGE; + } + } + } + } + + + if (lu->maxlun == 0) { + ISTGT_ERRLOG("LU%d: no LUN\n", lu->num); + goto error_return; + } + + /* tsih 0 is reserved */ + /*for (i = 0; i < MAX_LU_TSIH; i++) { + lu->tsih[i].tag = 0; + lu->tsih[i].tsih = 0; + lu->tsih[i].initiator_port = NULL; + } + lu->maxtsih = 1; + lu->last_tsih = 0; + + MTX_LOCK(&lu->istgt->mutex); + lu->istgt->nlogical_unit++; + lu->istgt->logical_unit[lu->num] = lu; + MTX_UNLOCK(&lu->istgt->mutex); */ + return 0; + +error_out: + for (i = 0; i < lu->maxmap; i++) { + ig_tag_i_new = lu->map[i].ig_tag; + MTX_LOCK(&lu->istgt->mutex); + igp_new = istgt_lu_find_initiatorgroup(lu->istgt, ig_tag_i_new); + if (igp_new != NULL) { + igp_new->ref--; + } + MTX_UNLOCK(&lu->istgt->mutex); + } + +error_return: + ISTGT_ERRLOG("Updating the logical unit failed LU%d\n",lu->num); + return -1; +} + + + +static int +istgt_lu_del_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu) +{ + PORTAL_GROUP *pgp; + INITIATOR_GROUP *igp; + int pg_tag_i, ig_tag_i; + int i, j; + + if (lu ==NULL) + return 0; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "del unit %d\n", lu->num); + + //MTX_LOCK(&istgt->mutex); + istgt->nlogical_unit--; + istgt->logical_unit[lu->num] = NULL; + //MTX_UNLOCK(&istgt->mutex); + + xfree(lu->name); + xfree(lu->alias); + xfree(lu->inq_vendor); + xfree(lu->inq_product); + xfree(lu->inq_revision); + xfree(lu->inq_serial); + for (i = 0; i < MAX_LU_LUN; i++) { + xfree(lu->lun[i].serial); + switch (lu->lun[i].type) { + case ISTGT_LU_LUN_TYPE_DEVICE: + xfree(lu->lun[i].u.device.file); + break; + case ISTGT_LU_LUN_TYPE_STORAGE: + xfree(lu->lun[i].u.storage.file); + break; + case ISTGT_LU_LUN_TYPE_REMOVABLE: + xfree(lu->lun[i].u.removable.file); + break; + case ISTGT_LU_LUN_TYPE_SLOT: + for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) { + xfree(lu->lun[i].u.slot.file[j]); + } + break; + case ISTGT_LU_LUN_TYPE_NONE: + default: + break; + } + } + for (i = 0; i < MAX_LU_TSIH; i++) { + xfree(lu->tsih[i].initiator_port); + } + for (i = 0; i < lu->maxmap; i++) { + pg_tag_i = lu->map[i].pg_tag; + ig_tag_i = lu->map[i].ig_tag; + //MTX_LOCK(&istgt->mutex); + pgp = istgt_lu_find_portalgroup(istgt, pg_tag_i); + igp = istgt_lu_find_initiatorgroup(istgt, ig_tag_i); + if (pgp != NULL && igp != NULL) { + pgp->ref--; + igp->ref--; + } + //MTX_UNLOCK(&istgt->mutex); + } + + return 0; +} + +static void *luworker(void *arg); + +static int istgt_lu_init_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu) +{ + int rc; + + rc = pthread_mutex_init(&lu->mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num); + return -1; + } + rc = pthread_mutex_init(&lu->state_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num); + return -1; + } + rc = pthread_mutex_init(&lu->queue_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num); + return -1; + } + rc = pthread_cond_init(&lu->queue_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: cond_init() failed\n", lu->num); + return -1; + } + + switch (lu->type) { + case ISTGT_LU_TYPE_PASS: + ISTGT_ERRLOG("LU%d: pass thru unsupported\n", lu->num); + return -1; + break; + + case ISTGT_LU_TYPE_DISK: + rc = istgt_lu_disk_init(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_init() failed\n", lu->num); + return -1; + } + break; + + case ISTGT_LU_TYPE_DVD: + ISTGT_ERRLOG("LU%d: dvd unsupported\n", lu->num); + return -1; + break; + + case ISTGT_LU_TYPE_TAPE: + ISTGT_ERRLOG("LU%d: tape unsupported\n", lu->num); + return -1; + break; + + case ISTGT_LU_TYPE_NONE: + //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num); + break; + default: + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + return 0; +} + +int +istgt_lu_init(ISTGT_Ptr istgt) +{ + ISTGT_LU_Ptr lu; + CF_SECTION *sp; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_init\n"); + sp = istgt_find_cf_section(istgt->config, "Global"); + if (sp == NULL) { + ISTGT_ERRLOG("find_cf_section failed()\n"); + return -1; + } + + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_LOGICAL_UNIT) { + if (sp->num == 0) { + ISTGT_ERRLOG("Unit 0 is invalid\n"); + return -1; + } + if (sp->num > ISTGT_LU_TAG_MAX) { + ISTGT_ERRLOG("tag %d is invalid\n", sp->num); + return -1; + } + rc = istgt_lu_add_unit(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("lu_add_unit() failed\n"); + return -1; + } + } + sp = sp->next; + } + + MTX_LOCK(&istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + rc = istgt_lu_init_unit(istgt, lu); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("LU%d: lu_init_unit() failed\n", lu->num); + return -1; + } + istgt_lu_set_state(lu, ISTGT_STATE_INITIALIZED); + } + MTX_UNLOCK(&istgt->mutex); + + return 0; +} + +static int +istgt_lu_exist_num(CONFIG *config, int num) +{ + CF_SECTION *sp; + + sp = config->section; + while (sp != NULL) { + if (sp->type == ST_LOGICAL_UNIT) { + if (sp->num == num) { + return 1; + } + } + sp = sp->next; + } + return -1; +} + +static int istgt_lu_shutdown_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); + +int +istgt_lu_reload_delete(ISTGT_Ptr istgt) +{ + ISTGT_LU_Ptr lu; + int warn_num, warn_msg; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_reload_delete\n"); + warn_num = warn_msg = 0; +retry: + MTX_LOCK(&istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + rc = istgt_lu_exist_num(istgt->config, lu->num); + if (rc < 0) { + MTX_LOCK(&lu->mutex); + if (lu->maxtsih > 1) { + if (!warn_msg) { + warn_msg = 1; + ISTGT_WARNLOG("It is recommended that you disconnect the target before deletion.\n"); + } + if (warn_num != lu->num) { + warn_num = lu->num; + ISTGT_WARNLOG("delete request for active LU%d\n", + lu->num); + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "reload retry for LU%d\n", + lu->num); + MTX_UNLOCK(&lu->mutex); + MTX_UNLOCK(&istgt->mutex); + istgt_yield(); + sleep(1); + goto retry; + } + MTX_UNLOCK(&lu->mutex); + istgt_lu_set_state(lu, ISTGT_STATE_SHUTDOWN); + rc = istgt_lu_shutdown_unit(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_shutdown_unit() failed\n", lu->num); + /* ignore error */ + } + ISTGT_NOTICELOG("delete LU%d: Name=%s\n", lu->num, lu->name); + xfree(lu); + istgt->logical_unit[i] = NULL; + } + } + MTX_UNLOCK(&istgt->mutex); + return 0; +} + +static int +istgt_lu_match_all(CF_SECTION *sp, CONFIG *config_old) +{ + CF_ITEM *ip, *ip_old; + CF_VALUE *vp, *vp_old; + CF_SECTION *sp_old; + + sp_old = istgt_find_cf_section(config_old, sp->name); + if (sp_old == NULL) + return 0; + + ip = sp->item; + ip_old = sp_old->item; + while (ip != NULL && ip_old != NULL) { + vp = ip->val; + vp_old = ip_old->val; + while (vp != NULL && vp_old != NULL) { + if (vp->value != NULL && vp_old->value != NULL) { + if (strcmp(vp->value, vp_old->value) != 0) + return 0; + } else { + return 0; + } + vp = vp->next; + vp_old = vp_old->next; + } + if (vp != NULL || vp_old != NULL) + return 0; + ip = ip->next; + ip_old = ip_old->next; + } + if (ip != NULL || ip_old != NULL) + return 0; + return 1; +} + +/*static int +istgt_lu_copy_sp(CF_SECTION *sp, CONFIG *config_old) +{ + CF_SECTION *sp_old; + + sp_old = istgt_find_cf_section(config_old, sp->name); + if (sp_old == NULL) + return -1; + istgt_copy_cf_item(sp, sp_old); + return 0; +}*/ + +static int istgt_lu_create_thread(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); + +int +istgt_lu_reload_update(ISTGT_Ptr istgt) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_Ptr lu_old; + CF_SECTION *sp; + int rc; + ISTGT_LU_DISK *spec = NULL; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_reload_update\n"); + + sp = istgt->config->section; + while (sp != NULL) { + if (sp->type == ST_LOGICAL_UNIT) { + if (sp->num == 0) { + ISTGT_ERRLOG("Unit 0 is invalid\n"); + goto skip_lu; + } + if (sp->num > ISTGT_LU_TAG_MAX) { + ISTGT_ERRLOG("tag %d is invalid\n", sp->num); + goto skip_lu; + } +#if 0 + rc = istgt_lu_exist_num(istgt->config_old, sp->num); +#else + rc = -1; + MTX_LOCK(&istgt->mutex); + lu = istgt->logical_unit[sp->num]; + if (lu != NULL) + rc = 1; + MTX_UNLOCK(&istgt->mutex); +#endif + if (rc < 0) { + rc = istgt_lu_add_unit(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("lu_add_unit() failed\n"); + goto skip_lu; + } + MTX_LOCK(&istgt->mutex); + lu = istgt->logical_unit[sp->num]; + if (lu == NULL) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("can't find new LU%d\n", sp->num); + goto skip_lu; + } + rc = istgt_lu_init_unit(istgt, lu); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("LU%d: lu_init_unit() failed\n", sp->num); + goto free_lu; + } + istgt_lu_set_state(lu, ISTGT_STATE_INITIALIZED); + + rc = istgt_lu_create_thread(istgt, lu); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("lu_create_thread() failed\n"); + goto skip_lu; + } + istgt_lu_set_state(lu, ISTGT_STATE_RUNNING); + ISTGT_NOTICELOG("add LU%d: Name=%s\n", lu->num, lu->name); + MTX_UNLOCK(&istgt->mutex); + } else { + if (istgt_lu_match_all(sp, istgt->config_old)) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "skip LU%d: Name=%s\n", lu->num, lu->name); + } else { + MTX_LOCK(&istgt->mutex); + lu = istgt->logical_unit[sp->num]; + if (lu == NULL) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("can't find LU%d\n", sp->num); + goto skip_lu; + } + MTX_LOCK(&lu->mutex); + if (lu->maxtsih > 1) { + /* ISTGT_ERRLOG("update active LU%d: Name=%s, " + "# of TSIH=%d\n", + lu->num, lu->name, lu->maxtsih - 1);*/ + //rc = istgt_lu_copy_sp(sp, istgt->config_old); + // if (rc < 0) { + /* ignore error */ + //} + MTX_UNLOCK(&lu->mutex); + MTX_UNLOCK(&istgt->mutex); + rc = istgt_lu_update_unit(lu, sp); + if (rc < 0) { + /* erro in updating the lu */ + } + spec = (ISTGT_LU_DISK *)(lu->lun[0].spec); + MTX_LOCK(&spec->complete_queue_mutex); + rc = pthread_cond_signal(&spec->maint_cmd_queue_cond); + MTX_UNLOCK(&spec->complete_queue_mutex); + goto skip_lu; + } else { + istgt->logical_unit[sp->num] = NULL; + MTX_UNLOCK(&lu->mutex); + MTX_UNLOCK(&istgt->mutex); + + /* add new LU */ + rc = istgt_lu_add_unit(istgt, sp); + if (rc < 0) { + ISTGT_ERRLOG("lu_add_unit() failed\n"); + MTX_LOCK(&istgt->mutex); + istgt->logical_unit[sp->num] = lu; + MTX_UNLOCK(&istgt->mutex); + goto skip_lu; + } else { + /* delete old LU */ + lu_old = lu; + MTX_LOCK(&istgt->mutex); + lu = istgt->logical_unit[sp->num]; + istgt_lu_set_state(lu_old, + ISTGT_STATE_SHUTDOWN); + rc = istgt_lu_shutdown_unit(istgt, + lu_old); + if (rc < 0) { + ISTGT_ERRLOG( + "LU%d: lu_shutdown_unit() " + "failed\n", lu->num); + /* ignore error */ + } + xfree(lu_old); + istgt->logical_unit[sp->num] = lu; + MTX_UNLOCK(&istgt->mutex); + } + MTX_LOCK(&istgt->mutex); + lu = istgt->logical_unit[sp->num]; + if (lu == NULL) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("can't find new LU%d\n", + sp->num); + goto skip_lu; + } + rc = istgt_lu_init_unit(istgt, lu); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("LU%d: lu_init_unit() " + "failed\n", sp->num); + goto free_lu; + } + istgt_lu_set_state(lu, + ISTGT_STATE_INITIALIZED); + + rc = istgt_lu_create_thread(istgt, lu); + if (rc < 0) { + MTX_UNLOCK(&istgt->mutex); + ISTGT_ERRLOG("lu_create_thread " + "failed\n"); + goto skip_lu; + } + istgt_lu_set_state(lu, ISTGT_STATE_RUNNING); + ISTGT_NOTICELOG("update LU%d: Name=%s\n", + lu->num, lu->name); + } + MTX_UNLOCK(&istgt->mutex); + } + } + } + goto skip_lu; + + free_lu: + ISTGT_NOTICELOG("free the lu\n"); + /* Delete LU */ + MTX_LOCK(&istgt->mutex); + istgt_lu_set_state(lu, + ISTGT_STATE_SHUTDOWN); + rc = istgt_lu_shutdown_unit(istgt, + lu); + if (rc < 0) { + ISTGT_ERRLOG( + "LU%d: lu_shutdown_unit() " + "failed\n", lu->num); + /* ignore error */ + } + ISTGT_NOTICELOG("delete LU%d: Name=%s\n", lu->num, lu->name); + xfree(lu); + istgt->logical_unit[sp->num] = NULL; + MTX_UNLOCK(&istgt->mutex); + + skip_lu: + sp = sp->next; + } + return 0; +} + +int istgt_lu_update_ig(ISTGT_Ptr istgt, INITIATOR_GROUP *igp_new) +{ + ISTGT_LU_Ptr lu; + int i, j; + + if (igp_new == NULL) + return 0; + ISTGT_NOTICELOG("initiator group update\n"); + for (i=0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + for (j=0; j < lu->maxmap; j++) { + if (lu->map[j].ig_tag == igp_new->tag) + istgt_lu_close_connection(lu, igp_new); + } + } + return 0; +} +int +istgt_lu_set_all_state(ISTGT_Ptr istgt, ISTGT_STATE state) +{ + ISTGT_LU_Ptr lu; + int i; + + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + + istgt_lu_set_state(lu, state); + } + + return 0; +} + +static void *maintenance_io_worker(void *arg); +static void *luscheduler(void *arg); + +static int +istgt_lu_create_thread(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu) +{ + int rc; + int i = 0; + + rc = pthread_create(&lu->schdler_thread, &istgt->attr, &luscheduler, + (void *)lu); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed ,lun %d, rc = %d\n", + lu->num, rc ); + return -1; + } + + if (lu->queue_depth != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "thread for LU%d\n", lu->num); + /* create LU thread */ + for ( i=0; i < lu->luworkers; i++ ) { + rc = pthread_create(&lu->luthread[i], &istgt->attr, &luworker, + (void *)lu); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed for thread %d, lun %d, rc = %d\n", + i, lu->num, rc ); + return -1; + } + ++lu->luworkersActive; + } + } + + rc = pthread_create(&lu->maintenance_thread, &istgt->attr, &maintenance_io_worker, + (void *)lu); + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed for maintenance thread ,lun %d, rc = %d\n", + lu->num, rc ); + return -1; + } + + return 0; +} + +int +istgt_lu_create_threads(ISTGT_Ptr istgt) +{ + ISTGT_LU_Ptr lu; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_create_threads\n"); + + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + rc = istgt_lu_create_thread(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("lu_create_thread() failed\n"); + return -1; + } + } + + return 0; +} + +static int +istgt_lu_shutdown_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu) +{ + int rc; + //int i = 0; + + switch (lu->type) { + case ISTGT_LU_TYPE_PASS: + ISTGT_ERRLOG("LU%d: lu_pass_shutdown() \n", lu->num); + break; + + case ISTGT_LU_TYPE_DISK: + rc = istgt_lu_disk_shutdown(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_shutdown() failed\n", lu->num); + /* ignore error */ + } + break; + + case ISTGT_LU_TYPE_DVD: + ISTGT_ERRLOG("LU%d: lu_dvd_shutdown()\n", lu->num); + break; + + case ISTGT_LU_TYPE_TAPE: + ISTGT_ERRLOG("LU%d: lu_tape_shutdown()\n", lu->num); + break; + + case ISTGT_LU_TYPE_NONE: + //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num); + break; + default: + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + rc = istgt_lu_del_unit(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_del_unit() failed\n", lu->num); + /* ignore error */ + } + + rc = pthread_cond_destroy(&lu->queue_cond); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: cond_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&lu->queue_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&lu->state_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&lu->mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + + return 0; +} + +int +istgt_lu_shutdown(ISTGT_Ptr istgt) +{ + ISTGT_LU_Ptr lu; + int rc; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_shutdown\n"); + MTX_LOCK(&istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + istgt_lu_set_state(lu, ISTGT_STATE_SHUTDOWN); + rc = istgt_lu_shutdown_unit(istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_shutdown_unit() failed\n", lu->num); + /* ignore error */ + } + xfree(lu); + istgt->logical_unit[i] = NULL; + } + MTX_UNLOCK(&istgt->mutex); + + return 0; +} + +int +istgt_lu_islun2lun(uint64_t islun) +{ + uint64_t fmt_lun; + uint64_t method; + int lun_i; + + fmt_lun = islun; + method = (fmt_lun >> 62) & 0x03U; + fmt_lun = fmt_lun >> 48; + if (method == 0x00U) { + lun_i = (int) (fmt_lun & 0x00ffU); + } else if (method == 0x01U) { + lun_i = (int) (fmt_lun & 0x3fffU); + } else { + lun_i = 0xffffU; + } + return lun_i; +} + +uint64_t +istgt_lu_lun2islun(int lun, int maxlun) +{ + uint64_t fmt_lun; + uint64_t method; + uint64_t islun; + + islun = (uint64_t) lun; + if (maxlun <= 0x0100) { + /* below 256 */ + method = 0x00U; + fmt_lun = (method & 0x03U) << 62; + fmt_lun |= (islun & 0x00ffU) << 48; + } else if (maxlun <= 0x4000) { + /* below 16384 */ + method = 0x01U; + fmt_lun = (method & 0x03U) << 62; + fmt_lun |= (islun & 0x3fffU) << 48; + } else { + /* XXX */ + fmt_lun = ~((uint64_t) 0); + } + return fmt_lun; +} + +int +istgt_lu_reset(ISTGT_LU_Ptr lu, uint64_t lun, istgt_ua_type ua_type) +{ + int lun_i; + int cleared = 0; + + if (lu == NULL) + return -1; + + lun_i = istgt_lu_islun2lun(lun); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: Name=%s, LUN=%d\n", + lu->num, lu->name, lun_i); + + switch (lu->type) { + case ISTGT_LU_TYPE_PASS: + ISTGT_ERRLOG("LU%d: pass_thru reset\n", lu->num); + break; + + case ISTGT_LU_TYPE_DISK: + cleared = istgt_lu_disk_reset(lu, lun_i, ua_type); + if (cleared < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_reset() failed\n", lu->num); + return -1; + } + return cleared; + break; + + case ISTGT_LU_TYPE_DVD: + ISTGT_ERRLOG("LU%d: dvd reset\n", lu->num); + break; + + case ISTGT_LU_TYPE_TAPE: + ISTGT_ERRLOG("LU%d: tape reset\n", lu->num); + break; + + case ISTGT_LU_TYPE_NONE: + //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num); + break; + default: + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + return 0; +} + +/* SAM3: Page 79, The target port shall perform + * logical unit reset functions for every logical unit. + * A unit attention condition for all initiators that + * have access shall be created on each of + * these logical units. + */ + +int +istgt_lu_reset_all(ISTGT_Ptr istgt, istgt_ua_type ua_type) +{ + int i = 0, j = 0; + int ret = 0; + int cleared = 0, clear_temp = 0; + ISTGT_LU_Ptr lu; + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + for (j = 0; j < lu->maxlun; j++) { + clear_temp = istgt_lu_reset(lu, j, ua_type); + if (clear_temp < 0) { + ISTGT_ERRLOG("istgt_lu_reset() failed, LU %d, LUN %d\n", lu->num, j); + ret = -1; + } else + cleared +=clear_temp; + } + } + return ((ret < 0) ? ret : cleared); +} + + +ISTGT_LU_TASK_Ptr +istgt_lu_create_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int lun, ISTGT_LU_DISK *spec) +{ + ISTGT_LU_TASK_Ptr lu_task = NULL; + ISCSI_PDU_Ptr dst_pdu, src_pdu; + uint8_t *cdb; + int alloc_len, i, gotlba=0; + int pbdata, lbdata, anchor; + int64_t maxlen; + uint64_t blkcnt = 0; +#if 0 + int rc; +#endif + + alloc_len = ISCSI_ALIGN(sizeof *lu_task); + alloc_len += ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu); + + lu_task = xmalloc(alloc_len); + if (lu_task == NULL) + return NULL; + + lu_task->type = ISTGT_LU_TASK_RESPONSE; + lu_task->conn = conn; + lu_task->in_plen = strlen(conn->initiator_port); + if (lu_task->in_plen > MAX_INITIATOR_NAME-1) + lu_task->in_plen = MAX_INITIATOR_NAME-1; + if (lu_task->in_plen != 0) { + strncpy(lu_task->in_port, conn->initiator_port, lu_task->in_plen); + lu_task->in_port[lu_task->in_plen] = '\0'; + } + else + lu_task->in_port[0] = '\0'; + lu_task->conn = conn; + + lu_task->lun = (int) lun; + lu_task->use_cond = 0; + lu_task->dup_iobuf = 0; + lu_task->alloc_len = 0; + + lu_task->lu_cmd._andx = lu_cmd->_andx; + lu_task->lu_cmd._lst = lu_cmd->_lst; + lu_task->lu_cmd._roll_cnt = 0; + for (i=0; i<= lu_cmd->_andx; ++i) { + lu_task->lu_cmd.times[i].tv_sec = lu_cmd->times[i].tv_sec; + lu_task->lu_cmd.times[i].tv_nsec = lu_cmd->times[i].tv_nsec; + lu_task->lu_cmd.tdiff[i].tv_sec = lu_cmd->tdiff[i].tv_sec; + lu_task->lu_cmd.tdiff[i].tv_nsec = lu_cmd->tdiff[i].tv_nsec; + lu_task->lu_cmd.caller[i] = lu_cmd->caller[i]; + lu_task->lu_cmd.line[i] = lu_cmd->line[i]; + } + for(; i < _PSZ;i++) { + lu_task->lu_cmd.times[i].tv_sec = 0; + lu_task->lu_cmd.times[i].tv_nsec = 0; + lu_task->lu_cmd.caller[i] = 0; + lu_task->lu_cmd.line[i] = 0; + lu_task->lu_cmd.tdiff[i].tv_sec = 0; + lu_task->lu_cmd.tdiff[i].tv_nsec = 0; + + } + + lu_task->condwait = 0; + lu_task->offset = 0; + lu_task->req_execute = 0; + lu_task->req_transfer_out = 0; + lu_task->error = 0; + lu_task->abort = 0; + lu_task->execute = 0; + lu_task->complete = 0; + lu_task->lock = 0; + lu_task->complete_queue_ptr = NULL; + lu_task->lu_cmd.flags = 0; +#if 0 + rc = pthread_mutex_init(&lu_task->trans_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + return -1; + } + rc = pthread_cond_init(&lu_task->trans_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + return -1; + } + rc = pthread_cond_init(&lu_task->exec_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("cond_init() failed\n"); + return -1; + } +#endif + lu_task->lu_cmd.pdu = (ISCSI_PDU_Ptr) ((uintptr_t)lu_task + + ISCSI_ALIGN(sizeof *lu_task)); + //lu_task->lu_cmd.pdu = xmalloc(sizeof *lu_task->lu_cmd.pdu); + //memset(lu_task->lu_cmd.pdu, 0, sizeof *lu_task->lu_cmd.pdu); + + /* copy PDU */ + dst_pdu = lu_task->lu_cmd.pdu; + src_pdu = lu_cmd->pdu; + memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN); + dst_pdu->ahs = src_pdu->ahs; + dst_pdu->header_digestX = src_pdu->header_digestX; + dst_pdu->data = src_pdu->data; + dst_pdu->data_digestX = src_pdu->data_digestX; + dst_pdu->total_ahs_len = src_pdu->total_ahs_len; + dst_pdu->data_segment_len = src_pdu->data_segment_len; + dst_pdu->opcode = src_pdu->opcode; + src_pdu->data = NULL; + src_pdu->data_segment_len = 0; + src_pdu->ahs = NULL; + src_pdu->total_ahs_len = 0; + + + /* copy other lu_cmd */ + lu_task->lu_cmd.lu = lu_cmd->lu; + cdb = ((uint8_t *) &lu_task->lu_cmd.pdu->bhs) + 32; + lu_task->lu_cmd.I_bit = lu_cmd->I_bit; + lu_task->lu_cmd.F_bit = lu_cmd->F_bit; + lu_task->lu_cmd.R_bit = lu_cmd->R_bit; + lu_task->lu_cmd.W_bit = lu_cmd->W_bit; + lu_task->lu_cmd.Attr_bit = lu_cmd->Attr_bit; + lu_task->lu_cmd.lun = lu_cmd->lun; + lu_task->lu_cmd.task_tag = lu_cmd->task_tag; + lu_task->lu_cmd.transfer_len = lu_cmd->transfer_len; + //lu_task->lu_cmd.cdb = lu_cmd->cdb; + lu_task->lu_cmd.cdb = cdb; + lu_task->lu_cmd.CmdSN = lu_cmd->CmdSN; + + //lu_task->lu_cmd.iobuf = lu_cmd->iobuf; + lu_task->lu_cmd.iobufindx = -1; + lu_task->lu_cmd.iobufsize = 0; + lu_task->lu_cmd.data = lu_cmd->data; + lu_task->lu_cmd.data_len = lu_cmd->data_len; + lu_task->lu_cmd.alloc_len = lu_cmd->alloc_len; + + lu_task->lu_cmd.status = lu_cmd->status; + lu_task->lu_cmd.sense_data = lu_cmd->sense_data; + lu_task->lu_cmd.sense_data_len = lu_cmd->sense_data_len; + lu_task->lu_cmd.sense_alloc_len = lu_cmd->sense_alloc_len; + lu_task->lu_cmd.cdb0 = lu_cmd->cdb0; + lu_task->lu_cmd.lba = lu_cmd->lba; + lu_task->lu_cmd.lblen = lu_cmd->lblen; + lu_task->lu_cmd.infdx = lu_cmd->infdx; + lu_task->lu_cmd.cdbflags = lu_cmd->cdbflags; + lu_task->lu_cmd.infcpy = lu_cmd->infcpy; + lu_task->lu_cmd.lunum = lu_cmd->lunum; + lu_task->lu_cmd.connGone = 0; + lu_task->lu_cmd.aborted = 0; + lu_task->lu_cmd.release_aborted = 0; + + lu_task->alloc_len = 0; //alloc_len; + + lu_task->cdb0 = cdb[0]; + lu_task->lba = 0; + lu_task->lblen = 0; + lu_task->lbE = 0; + + switch(cdb[0]) { + case SBC_READ_6: + case SBC_WRITE_6: + lu_task->lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU); + lu_task->lblen = (uint32_t) DGET8(&cdb[4]); + gotlba = 1; + break; + case SBC_READ_10: + case SBC_WRITE_10: + case SBC_WRITE_AND_VERIFY_10: + lu_task->lba = (uint64_t) DGET32(&cdb[2]); + lu_task->lblen = (uint32_t) DGET16(&cdb[7]); + gotlba = 1; + break; + case SBC_READ_12: + case SBC_WRITE_12: + case SBC_WRITE_AND_VERIFY_12: + lu_task->lba = (uint64_t) DGET32(&cdb[2]); + lu_task->lblen = (uint32_t) DGET32(&cdb[6]); + gotlba = 1; + break; + case SBC_READ_16: + case SBC_WRITE_16: + case SBC_WRITE_AND_VERIFY_16: + lu_task->lba = (uint64_t) DGET64(&cdb[2]); + lu_task->lblen = (uint32_t) DGET32(&cdb[10]); + gotlba = 1; + break; + + case SBC_WRITE_SAME_10: + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + if (pbdata || lbdata) { + //we don't support this + } else { + lu_task->lba = (uint64_t) DGET32(&cdb[2]); + lu_task->lblen = (uint32_t) DGET16(&cdb[7]); + gotlba = 1; + if (lu_task->lblen == 0) { + if (lu_task->lba < spec->blockcnt) { + blkcnt = spec->blockcnt - lu_task->lba; + lu_task->lblen = (uint32_t)blkcnt; + } else { + lu_task->lba = 0; + gotlba = 0; + } + } + } + break; + case SBC_WRITE_SAME_16: + anchor = BGET8(&cdb[1], 4); + //int unmap = BGET8(&cdb[1], 3); + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + if (pbdata || lbdata || anchor) { + //we don't support this + } else { + lu_task->lba = (uint64_t) DGET32(&cdb[2]); + lu_task->lblen = (uint32_t) DGET32(&cdb[10]); + gotlba = 1; + if (lu_task->lblen == 0) { + if (lu_task->lba < spec->blockcnt) { + blkcnt = spec->blockcnt - lu_task->lba; + lu_task->lblen = (uint32_t)blkcnt; + } else { + lu_task->lba = 0; + gotlba = 0; + } + } + } + break; + case SBC_COMPARE_AND_WRITE: + maxlen = ISTGT_LU_WORK_ATS_BLOCK_SIZE / spec->blocklen; + if (maxlen > 0xff) + maxlen = 0xff; + lu_task->lba = (uint64_t) DGET64(&cdb[2]); + lu_task->lblen = (uint32_t) DGET8(&cdb[13]); + if (lu_task->lblen > maxlen) { // invalid + lu_task->lba = 0; + lu_task->lblen = 0; + } else { + gotlba = 1; + } + break; + + case SBC_SYNCHRONIZE_CACHE_10: + lu_task->lba = (uint64_t) DGET32(&cdb[2]); + lu_task->lblen = (uint32_t) DGET16(&cdb[7]); + if (lu_task->lblen == 0) { + lu_task->lblen = (uint32_t) spec->blockcnt; + blkcnt = spec->blockcnt; + } + gotlba = 1; + break; + case SBC_SYNCHRONIZE_CACHE_16: + lu_task->lba = (uint64_t) DGET64(&cdb[2]); + lu_task->lblen = (uint32_t) DGET32(&cdb[10]); + if (lu_task->lblen == 0) { + lu_task->lblen = (uint32_t)spec->blockcnt; + blkcnt = spec->blockcnt; + } + gotlba = 1; + break; + + case SBC_UNMAP: + /*presently unmap is serializing all reads and writes*/ + break; + + default: + lu_task->cdb0 = 0xFF; + lu_task->lba = 0; + lu_task->lblen = 0; + lu_task->lbE = 0; + } + + if (gotlba == 1) { + if (blkcnt != 0) { + lu_task->lbE = lu_task->lba + blkcnt - 1; + } else { + if (lu_task->lblen > 0) + lu_task->lbE = lu_task->lba + lu_task->lblen - 1; + else //would never be here + lu_task->lbE = lu_task->lba; + } + lu_task->lu_cmd.lblen = lu_task->lblen; + } + /* + if (lu_task->cdb0 != lu_task->lu_cmd.cdb0 || + lu_task->lba != lu_task->lu_cmd.lba || + lu_task->lblen != lu_task->lu_cmd.lblen) { + log/fix + } + */ + + /* creation time */ + /* wait time */ + lu_task->condwait = conn->timeout; + if (lu_task->condwait < ISTGT_CONDWAIT_MINS) { + lu_task->condwait = ISTGT_CONDWAIT_MINS; + } + + return lu_task; +} + +int +istgt_lu_destroy_task(ISTGT_LU_TASK_Ptr lu_task) +{ + int rc, i; + + if (lu_task == NULL) + return -1; + + if (lu_task->use_cond != 0) { + rc = pthread_mutex_destroy(&lu_task->trans_mutex); + if (rc != 0) { + ISTGT_ERRLOG("mutex_destroy() failed\n"); + return -1; + } + rc = pthread_cond_destroy(&lu_task->trans_cond); + if (rc != 0) { + ISTGT_ERRLOG("cond_destroy() failed\n"); + return -1; + } + rc = pthread_cond_destroy(&lu_task->exec_cond); + if (rc != 0) { + ISTGT_ERRLOG("cond_destroy() failed\n"); + return -1; + } + } + if (lu_task->lu_cmd.pdu != NULL) { + if (lu_task->lu_cmd.pdu->ahs != NULL) { + xfree(lu_task->lu_cmd.pdu->ahs); + lu_task->lu_cmd.pdu->ahs = NULL; + } + if (lu_task->lu_cmd.pdu->data != NULL) { + xfree(lu_task->lu_cmd.pdu->data); + lu_task->lu_cmd.pdu->data = NULL; + } + //xfree(lu_task->lu_cmd.pdu); + } + if (lu_task->lu_cmd.data != NULL) { + xfree(lu_task->lu_cmd.data); + lu_task->lu_cmd.data = NULL; + } + if (lu_task->lu_cmd.sense_data != NULL) { + xfree(lu_task->lu_cmd.sense_data); + lu_task->lu_cmd.sense_data = NULL; + } + if (lu_task->lu_cmd.iobufindx != -1) { + for (i=0; i<=lu_task->lu_cmd.iobufindx; ++i) { + if (lu_task->lu_cmd.iobuf[i].iov_base) { + xfree(lu_task->lu_cmd.iobuf[i].iov_base); + lu_task->lu_cmd.iobuf[i].iov_base = NULL; + lu_task->lu_cmd.iobuf[i].iov_len = 0; + } + } + lu_task->lu_cmd.iobufindx = -1; + lu_task->lu_cmd.iobufsize = 0; + } + xfree(lu_task); + return 0; +} + +int +istgt_lu_clear_task_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu) +{ + int cleared = 0; + + if (lu == NULL) + return -1; + + if (lu->queue_depth == 0) + return 0; + + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + cleared = istgt_lu_disk_queue_clear_IT(conn, lu); + if (cleared < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_IT() failed\n", lu->num); + return -1; + } + break; + + case ISTGT_LU_TYPE_DVD: + case ISTGT_LU_TYPE_TAPE: + case ISTGT_LU_TYPE_NONE: + default: + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + return cleared; +} + +int +istgt_lu_clear_task_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun) +{ + int lun_i; + int cleared = 0; + + if (lu == NULL) + return -1; + if (lu->queue_depth == 0) + return 0; + if (lu->type != ISTGT_LU_TYPE_DISK) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + lun_i = istgt_lu_islun2lun(lun); + + cleared = istgt_lu_disk_queue_clear_ITL(conn, lu, lun_i); + if (cleared < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITL() failed\n", lu->num); + return -1; + } + return cleared; +} + +int +istgt_lu_clear_task_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun, uint32_t CmdSN) +{ + int lun_i; + int cleared = 0; + + if (lu == NULL) + return -1; + + if (lu->queue_depth == 0) + return 0; + if (lu->type != ISTGT_LU_TYPE_DISK) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + lun_i = istgt_lu_islun2lun(lun); + + cleared = istgt_lu_disk_queue_clear_ITLQ(conn, lu, lun_i, CmdSN); + if (cleared < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITLQ() failed\n", lu->num); + return -1; + } + return cleared; +} + +int +istgt_lu_clear_all_task(ISTGT_LU_Ptr lu, uint64_t lun) +{ + int cleared = 0; + + if (lu == NULL) + return -1; + + if (lu->queue_depth == 0) + return 0; + + if (lu->type != ISTGT_LU_TYPE_DISK) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + cleared = istgt_lu_disk_queue_clear_all(lu, lun); + if (cleared < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_all() failed\n", lu->num); + return -1; + } + return cleared; +} + +static void +luw_cleanup(void *arg) +{ + ISTGT_WARNLOG("luworker:%p thread_exit\n", arg); +} + +static void * +maintenance_io_worker(void *arg) +{ + ISTGT_LU_Ptr lu = (ISTGT_LU_Ptr) arg; + ISTGT_LU_DISK *spec = NULL; + ISTGT_LU_TASK_Ptr lu_task; + int qcnt; + int lun; + int rc = 0, i, j; + int retry_runningstate_count = 0; + int tind = 0; + int do_open, do_close; + errno = 0; + + pthread_t self = pthread_self(); + + i = lu->luworkers + 0; + if(lu->maintenance_thread == self) { + tind = i; + snprintf(tinfo, sizeof tinfo, "mt#%d.%ld.%d", lu->num, (uint64_t)(((uint64_t *)self)[0]), i); + pthread_set_name_np(lu->maintenance_thread, tinfo); + for (j = 0; j< lu->maxlun; j++) { + spec = (ISTGT_LU_DISK *) lu->lun[j].spec; + spec->inflight_io[i] = NULL; + } + } + else + { + ISTGT_ERRLOG("no match for maintenance thread\n"); + goto loop_exit; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d:%d loop start before running\n", lu->num, tind); + while (istgt_get_state(lu->istgt) != ISTGT_STATE_RUNNING) { + if (istgt_get_state(lu->istgt) == ISTGT_STATE_EXITING + || istgt_get_state(lu->istgt) == ISTGT_STATE_SHUTDOWN) { + ISTGT_ERRLOG("exit before running\n"); + return NULL; + } + //ISTGT_WARNLOG("Wait for running\n"); + sleep(1); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d:%d loop start waiting\n", lu->num, tind); + continue; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d:%d loop start\n", lu->num, tind); + lun = 0; + qcnt = 0; + pthread_cleanup_push(luw_cleanup, (void *)spec); + + while (1) { + if (lu->type != ISTGT_LU_TYPE_DISK) + break; + while (1) { + while ( (retry_runningstate_count < ISTGT_MAX_LU_RUNNING_STATE_RETRY_COUNT ) && + (istgt_lu_get_state(lu) == ISTGT_STATE_INITIALIZED) ) { + sleep(1); + retry_runningstate_count++; + } + + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + goto loop_exit; + + if (lun >= lu->maxlun) { + lun = 0; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + MTX_LOCK(&spec->complete_queue_mutex); +again: + do{ + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + goto loop_exit; + } + if(spec->schdler_cmd_waiting == 1) + { + if(unlikely((qcnt = istgt_queue_count(&spec->cmd_queue)) != 0)) + pthread_cond_signal(&spec->cmd_queue_cond); + else + istgt_schedule_blocked_requests(spec, &spec->cmd_queue, &spec->blocked_queue, 0);//0 for command queues + if((qcnt = istgt_queue_count(&spec->cmd_queue)) != 0) + pthread_cond_signal(&spec->cmd_queue_cond); + } + if((qcnt = istgt_queue_count(&spec->maint_cmd_queue)) == 0) + istgt_schedule_blocked_requests(spec, &spec->maint_cmd_queue, &spec->maint_blocked_queue, 1);//1 for maintenance queues + if(((qcnt = istgt_queue_count(&spec->maint_cmd_queue)) == 0) && (spec->disk_modify_work_pending == 0) && (!(spec->rsv_pending & ISTGT_RSV_READ)) ) + { + spec->maint_thread_waiting = 1; + pthread_cond_wait(&spec->maint_cmd_queue_cond, &spec->complete_queue_mutex); + spec->maint_thread_waiting = 0; + + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + goto loop_exit; + } + } + } while (( (qcnt = istgt_queue_count(&spec->maint_cmd_queue)) == 0) && (spec->disk_modify_work_pending == 0) && (!(spec->rsv_pending & ISTGT_RSV_READ))); + + if(unlikely(spec->disk_modify_work_pending == 1)) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + do_open = 0; do_close = 0; + MTX_LOCK(&spec->state_mutex); + if (spec->ex_state == ISTGT_LUN_CLOSE_PENDING) { + do_close = 1; + if (spec->open_waiting4close == 1) //open after the pending close + do_open = 1; + } else if (spec->ex_state == ISTGT_LUN_OPEN_PENDING) { + do_open = 1; + } + MTX_UNLOCK(&spec->state_mutex); + if (do_close == 1) + rc = istgt_lu_disk_close(spec->lu, spec->lun); + if (do_open == 1) + rc = istgt_lu_disk_open(spec->lu, spec->lun); + + MTX_LOCK(&spec->complete_queue_mutex); + if(rc == 0) + spec->disk_modify_work_pending = 0; + else { + lu_task = istgt_queue_dequeue(&spec->maint_cmd_queue); + if(lu_task != NULL) { + goto execute_task; + } + else { + MTX_UNLOCK(&spec->complete_queue_mutex); + sleep(1); + MTX_LOCK(&spec->complete_queue_mutex); + } + } + /* Lock is not released here */ + goto again; + } + MTX_UNLOCK(&spec->complete_queue_mutex); + MTX_LOCK(&spec->pr_rsv_mutex); + if(unlikely(spec->rsv_pending & ISTGT_RSV_READ)) { + MTX_UNLOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_post_open(spec); + if(rc != 0) { + MTX_LOCK(&spec->complete_queue_mutex); + lu_task = istgt_queue_dequeue(&spec->maint_cmd_queue); + if(lu_task != NULL) { + goto execute_task; + } + else { + MTX_UNLOCK(&spec->complete_queue_mutex); + sleep(1); + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + goto loop_exit; + } + } + MTX_LOCK(&spec->complete_queue_mutex); + goto again; + } + else + MTX_UNLOCK(&spec->pr_rsv_mutex); + MTX_LOCK(&spec->complete_queue_mutex); + lu_task = istgt_queue_dequeue(&spec->maint_cmd_queue); + if(lu_task == NULL) { + goto again; + } +execute_task: + MTX_LOCK(&spec->luworker_mutex[tind]); + spec->inflight_io[tind] = lu_task; + lu_task->conn->inflight++; + MTX_UNLOCK(&spec->complete_queue_mutex); + MTX_UNLOCK(&spec->luworker_mutex[tind]); + + lu_task->lu_cmd.flags |= ISTGT_MAINT_WORKER_PICKED; + rc = istgt_lu_disk_queue_start(lu, lun, tind); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_start() %s %d\n", + lu->num, rc == -2 ? "aborted" : "failed", rc); + } + + lun++; + } + } + loop_exit: + ; + pthread_cleanup_pop(0); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop ended\n", lu->num); + return NULL; +} + +static void * +luworker(void *arg) +{ + ISTGT_LU_Ptr lu = (ISTGT_LU_Ptr) arg; + ISTGT_LU_DISK *spec = NULL; + ISTGT_LU_TASK_Ptr lu_task; + int lun; + int rc, i, j, oldtimeset = 0; + int retry_runningstate_count = 0; + int tind = 0; + struct timespec now1, r, oldtime, first, second2, third; + int id; + unsigned long secs, nsecs; + + oldtime.tv_sec = 0; + oldtime.tv_nsec = 0; +#define tdiff(_s, _n, _r) { \ + if(unlikely(spec->do_avg == 1)) \ + { \ + if ((_n.tv_nsec - _s.tv_nsec) < 0) { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec-1; \ + _r.tv_nsec = 1000000000 + _n.tv_nsec - _s.tv_nsec; \ + } else { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec; \ + _r.tv_nsec = _n.tv_nsec - _s.tv_nsec; \ + } \ + spec->avgs[id].count++; \ + spec->avgs[id].tot_sec += _r.tv_sec; \ + spec->avgs[id].tot_nsec += _r.tv_nsec; \ + secs = spec->avgs[id].tot_nsec/1000000000; \ + nsecs = spec->avgs[id].tot_nsec%1000000000; \ + spec->avgs[id].tot_sec += secs; \ + spec->avgs[id].tot_nsec = nsecs; \ + } \ +} + + pthread_t self = pthread_self(); + for (i= 0; i < lu->luworkers; i++ ) { + if (lu->luthread[i] == self) { + tind = i; + snprintf(tinfo, sizeof tinfo, "l#%d.%ld.%d", lu->num, (uint64_t)(((uint64_t *)self)[0]), i); + pthread_set_name_np(lu->luthread[i], tinfo); + for (j = 0; j< lu->maxlun; j++) { + spec = (ISTGT_LU_DISK *) lu->lun[j].spec; + spec->inflight_io[i] = NULL; + } + break; + } + } + + while (istgt_get_state(lu->istgt) != ISTGT_STATE_RUNNING) { + if (istgt_get_state(lu->istgt) == ISTGT_STATE_EXITING + || istgt_get_state(lu->istgt) == ISTGT_STATE_SHUTDOWN) { + ISTGT_ERRLOG("exit before running\n"); + return NULL; + } + sleep(1); + continue; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop start\n", lu->num); + lun = 0; + for (j = 0; j< lu->maxlun; j++) { + spec = (ISTGT_LU_DISK *) lu->lun[j].spec; + MTX_LOCK(&spec->luworker_mutex[tind]); + if ( likely(spec->inflight_io[tind] == NULL)) { + MTX_LOCK(&spec->schdler_mutex); + if( likely(BGET32(spec->lu_free_matrix[(tind >> 5)], (tind & 31)) == 0)){ + BSET32(spec->lu_free_matrix[(tind >> 5)], (tind & 31)); + pthread_cond_signal(&spec->schdler_cond); + } else { + spec->error_count++; + ISTGT_ERRLOG("LU%d: Error thread %d\n", lu->num, tind); + } + MTX_UNLOCK(&spec->schdler_mutex); + } else { + spec->error_count++; + ISTGT_ERRLOG("LU%d: Error thread %d: inflight is not NULL \n", lu->num, tind); + } + MTX_UNLOCK(&spec->luworker_mutex[tind]); + } + + while (1) { + if (lu->type != ISTGT_LU_TYPE_DISK) + break; + while (1) { + /* + * Change necessitated by kill -HUP of istgt for lu_reload case: + * The lu state is set to RUNNING by reload_delete once all threads + * have been created. + * But this causes a race when already spawned luworkers arrive + * at this check point to find the state is non-RUNNING; the threads + * ie. luworkers exit (usually due to the timing associated with + * pthread_create( luworker ), one of the luworkers manages to spawn + * and correctly find the state as RUNNING at this point so it continues + * while other 5 (default value of 6 luworkers per lun) exit + * + * To prevent this, lets retry giving more time for all threads to be + * spawned and arrive here, so caller istgt_lu_reload_update can set the + * lu state to RUNNING. + * + * checking for state RUNNING leads to the code taking too much time + * in the shutdown path. So simply check for INITIALIZED, expecting + * the transition to RUNNING. If it times out without getting the + * RUNNING state, bail + */ + clock_gettime(clockid, &first); + while ( (retry_runningstate_count < ISTGT_MAX_LU_RUNNING_STATE_RETRY_COUNT ) && + (istgt_lu_get_state(lu) == ISTGT_STATE_INITIALIZED) ) { + sleep(1); + retry_runningstate_count++; + } + + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + goto loop_exit; + + id = 14; + clock_gettime(clockid, &second2); + tdiff(first, second2, r); + if (lun >= lu->maxlun) { + lun = 0; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + MTX_LOCK(&spec->luworker_mutex[tind]); + while ( spec->inflight_io[tind] == NULL) { + if(unlikely(BGET32(spec->lu_free_matrix[(tind >> 5)], (tind & 31)) == 0)) + { + MTX_LOCK(&spec->schdler_mutex); + if( BGET32(spec->lu_free_matrix[(tind >> 5)], (tind & 31)) == 0) { + spec->error_count++; + ISTGT_ERRLOG("LU%d: Error thread %d busy\n", lu->num, tind); + BSET32(spec->lu_free_matrix[(tind >> 5)], (tind & 31)); + } + MTX_UNLOCK(&spec->schdler_mutex); + } + clock_gettime(clockid, &first); + if(unlikely(spec->do_avg == 1)) + { + spec->avgs[8].count++; + spec->avgs[9].count++; + spec->avgs[11].count++; + + spec->avgs[8].tot_sec += istgt_queue_count(&spec->cmd_queue); + spec->avgs[9].tot_sec += istgt_queue_count(&spec->blocked_queue); + spec->avgs[11].tot_sec += spec->inflight; + } + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->luworker_mutex[tind]); + goto loop_exit; + } + spec->luworker_waiting[tind] = 1; + pthread_cond_wait(&spec->luworker_cond[tind], &spec->luworker_mutex[tind]); + spec->luworker_waiting[tind] = 0; + + if(unlikely(spec->do_avg == 1)) + { + spec->avgs[8].tot_nsec += istgt_queue_count(&spec->cmd_queue); + spec->avgs[9].tot_nsec += istgt_queue_count(&spec->blocked_queue); + spec->avgs[11].tot_nsec += spec->inflight; + } + clock_gettime(clockid, &second2); + id = 17; + tdiff(first, second2, r); + MTX_UNLOCK(&spec->luworker_mutex[tind]); + + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + goto loop_exit; + MTX_LOCK(&spec->luworker_mutex[tind]); + } + lu_task = spec->inflight_io[tind]; + MTX_UNLOCK(&spec->luworker_mutex[tind]); + + if(unlikely(lu->limit_q_size != 0 && + tind == 0)) + usleep(50000); //50ms + + clock_gettime(clockid, &third); + id = 16; + tdiff(second2, third, r); + lu_task->lu_cmd.flags |= ISTGT_WORKER_PICKED; + rc = istgt_lu_disk_queue_start(lu, lun, tind); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_start() %s %d\n", + lu->num, rc == -2 ? "aborted" : "failed", rc); + } + + clock_gettime(clockid, &now1); + id = 12; + tdiff(third, now1, r); + if(oldtimeset == 1) + { + id = 13; + tdiff(oldtime, third, r); + } + oldtime = now1; + oldtimeset = 1; + + lun++; + } + } + loop_exit: + ; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop ended\n", lu->num); + return NULL; +} + +static void * +luscheduler(void *arg) +{ + ISTGT_LU_Ptr lu = (ISTGT_LU_Ptr) arg; + ISTGT_LU_DISK *spec = (ISTGT_LU_DISK *) lu->lun[0].spec; + ISTGT_LU_TASK_Ptr lu_task; + int retry_runningstate_count = 0; + struct timespec sch1, sch2, sch3, sch4, sch5,sch6, r; + int qcnt = 0, ind = 0; + int worker_id; + int id, found_worker = 0; + unsigned long secs, nsecs; +#define tdiff(_s, _n, _r) { \ + if(unlikely(spec->do_avg == 1)) \ + { \ + if ((_n.tv_nsec - _s.tv_nsec) < 0) { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec-1; \ + _r.tv_nsec = 1000000000 + _n.tv_nsec - _s.tv_nsec; \ + } else { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec; \ + _r.tv_nsec = _n.tv_nsec - _s.tv_nsec; \ + } \ + spec->avgs[id].count++; \ + spec->avgs[id].tot_sec += _r.tv_sec; \ + spec->avgs[id].tot_nsec += _r.tv_nsec; \ + secs = spec->avgs[id].tot_nsec/1000000000; \ + nsecs = spec->avgs[id].tot_nsec%1000000000; \ + spec->avgs[id].tot_sec += secs; \ + spec->avgs[id].tot_nsec = nsecs; \ + } \ +} + + + pthread_t sf = pthread_self(); + snprintf(tinfo, sizeof tinfo, "sh#%d.%ld.%d", lu->num, (uint64_t)(((uint64_t *)sf)[0]), 0); + pthread_set_name_np(lu->schdler_thread, tinfo); + while (istgt_get_state(lu->istgt) != ISTGT_STATE_RUNNING) { + if (istgt_get_state(lu->istgt) == ISTGT_STATE_EXITING + || istgt_get_state(lu->istgt) == ISTGT_STATE_SHUTDOWN) { + ISTGT_ERRLOG("exit before running\n"); + return NULL; + } + //ISTGT_WARNLOG("Wait for running\n"); + sleep(1); + continue; + } + while(1) { + /* Take the scheduler mutex lock, find if any of the luworkers are free from spec->lu_free_matrix. + * If so find the index of the least significant bit set in the spec->lu_free_matrix to get the + * luworker's id. If the all the luworkers are busy, then wait on schdler_cond variable. + */ +start: + while ( (retry_runningstate_count < ISTGT_MAX_LU_RUNNING_STATE_RETRY_COUNT ) && + (istgt_lu_get_state(lu) == ISTGT_STATE_INITIALIZED) ) { + sleep(1); + retry_runningstate_count++; + } + + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + goto loop_exit; + + clock_gettime(clockid, &sch1); + ind = 0; + MTX_LOCK(&spec->schdler_mutex); + while(ind <= (ISTGT_MAX_NUM_LUWORKERS/32)) { + found_worker = ((spec->lu_free_matrix[ind] != 0) && + ((lu->limit_q_size == 0) || ((ind == 0) && ((spec->lu_free_matrix[ind] & 1) == 1)))) + ? 1 : 0; + if (found_worker == 0) { + if (ind == (ISTGT_MAX_NUM_LUWORKERS/32)) { + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->schdler_mutex); + goto loop_exit; + } + spec->schdler_waiting = 1; + pthread_cond_wait(&spec->schdler_cond, &spec->schdler_mutex); + spec->schdler_waiting = 0; + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->schdler_mutex); + goto loop_exit; + } + ind = 0; + } else + ind++; + } else { + break; + } + } + MTX_UNLOCK(&spec->schdler_mutex); +next_lu_worker: + if ((worker_id = ffs(spec->lu_free_matrix[ind])) <= 0) + goto start; + worker_id--; //Bits are numbered starting at 1, the least significant bit. + worker_id += (ind<<5); + + if(worker_id >= spec->luworkers) //worker_id can't be >= luworkers + goto start; + + clock_gettime(clockid, &sch2); + id = 15; + tdiff(sch1, sch2, r); + + clock_gettime(clockid, &sch4); + + /* Try to schedule the blocked request and get the cmd_queue count, + * if count is zero wait on spec->cmd_queue_cond. If count > 0, dequeue the + * first request in the queue and assign it the luworker that is free and unset + * the bit in the free_matrix + */ + clock_gettime(clockid, &sch5); + id = 21; + tdiff(sch4, sch5, r); + MTX_LOCK(&spec->complete_queue_mutex); + do { + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + goto loop_exit; + } + if(spec->maint_thread_waiting == 1) + { + if(unlikely((qcnt = istgt_queue_count(&spec->maint_cmd_queue)) != 0)) + pthread_cond_signal(&spec->maint_cmd_queue_cond); + else + istgt_schedule_blocked_requests(spec, &spec->maint_cmd_queue, &spec->maint_blocked_queue, 1);//1 for maint queues + if((qcnt = istgt_queue_count(&spec->maint_cmd_queue)) != 0) + pthread_cond_signal(&spec->maint_cmd_queue_cond); + } + + if((qcnt = istgt_queue_count(&spec->cmd_queue)) == 0) + istgt_schedule_blocked_requests(spec, &spec->cmd_queue, &spec->blocked_queue, 0);//0 for cmd queues + if((qcnt = istgt_queue_count(&spec->cmd_queue)) == 0) { + spec->schdler_cmd_waiting = 1; + pthread_cond_wait(&spec->cmd_queue_cond, &spec->complete_queue_mutex); + spec->schdler_cmd_waiting = 0; + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + goto loop_exit; + } + } + } while ((qcnt = istgt_queue_count(&spec->cmd_queue)) == 0); + clock_gettime(clockid, &sch6); + id = 22; + tdiff(sch5, sch6, r); + if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) + { + MTX_UNLOCK(&spec->complete_queue_mutex); + goto loop_exit; + } + if (qcnt < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_queue_count() failed:%d\n", + lu->num, qcnt); + } + lu_task = istgt_queue_dequeue(&spec->cmd_queue); + clock_gettime(clockid, &sch3); + id = 19; + tdiff(sch5, sch3, r); + + MTX_LOCK(&spec->luworker_mutex[worker_id]); + if(likely(spec->inflight_io[worker_id] == NULL)) { + spec->inflight_io[worker_id] = lu_task; + lu_task->conn->inflight++; + lu_task->lu_cmd.flags |= ISTGT_SCHEDULED; + MTX_UNLOCK(&spec->complete_queue_mutex); + }else { + spec->error_count++; + istgt_queue_enqueue_first(&spec->cmd_queue,lu_task); + MTX_UNLOCK(&spec->complete_queue_mutex); + MTX_UNLOCK(&spec->luworker_mutex[worker_id]); + if ((spec->lu_free_matrix[ind] > 0) && + (likely(lu->limit_q_size == 0))) + goto next_lu_worker; + else + continue; + } + + MTX_LOCK(&spec->schdler_mutex); + spec->inflight++; + BUNSET32(spec->lu_free_matrix[(worker_id >> 5)], (worker_id&31)); + MTX_UNLOCK(&spec->schdler_mutex); + if(spec->luworker_waiting[worker_id]){ + MTX_UNLOCK(&spec->luworker_mutex[worker_id]); + pthread_cond_signal(&spec->luworker_cond[worker_id]); + } else { + MTX_UNLOCK(&spec->luworker_mutex[worker_id]); + } + if ((spec->lu_free_matrix[ind] > 0) && + (likely(lu->limit_q_size == 0))) + goto next_lu_worker; + } + loop_exit: + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "scheduler loop ended\n"); + return NULL; +} diff --git a/src/istgt_lu.h b/src/istgt_lu.h new file mode 100644 index 00000000..bbcb9125 --- /dev/null +++ b/src/istgt_lu.h @@ -0,0 +1,929 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_LU_H +#define ISTGT_LU_H + +#include +#include +#ifdef HAVE_UUID_H +#include +#endif +#include "istgt.h" +#include "istgt_queue.h" + +#ifdef __linux__ +#include +#endif + +#ifdef __FreeBSD__ +#include +/* IOCTL to Write/Read persistent Reservation and Registration data to/from zvol ZAP attribute */ +#define DIOCGWRRSV _IOW('d', 144, struct scsi_pr_data) /* Write pr data */ +#define DIOCGRDRSV _IOR('d', 145, struct scsi_pr_data) /* Read pr data */ +#endif + +#include +#define MAX_LU_LUN 64 +#define MAX_LU_LUN_SLOT 8 +#define MAX_LU_TSIH 256 +#define MAX_LU_MAP 256 +#define MAX_LU_SERIAL_STRING 32 +#define MAX_LU_RESERVE 256 +#define MAX_LU_ZAP_RESERVE 8 +#define MAX_LU_RESERVE_IPT 256 +#define MAX_LU_QUEUE_DEPTH 256 + +#define USE_LU_TAPE_DLT8000 + +#define DEFAULT_LU_BLOCKLEN 512 +#define DEFAULT_LU_BLOCKLEN_DISK DEFAULT_LU_BLOCKLEN +#define DEFAULT_LU_BLOCKLEN_DVD 2048 +#define DEFAULT_LU_BLOCKLEN_TAPE DEFAULT_LU_BLOCKLEN +#define DEFAULT_LU_QUEUE_DEPTH 32 +#define DEFAULT_LU_ROTATIONRATE 7200 /* 7200 rpm */ +#define DEFAULT_LU_FORMFACTOR 0x02 /* 3.5 inch */ + +#if defined (__linux__) +#define DEFAULT_LU_VENDOR "linux" +#elif defined (__FreeBSD__) +#define DEFAULT_LU_VENDOR "FreeBSD" +#elif defined (__NetBSD__) +#define DEFAULT_LU_VENDOR "NetBSD" +#elif defined (__OpenBSD__) +#define DEFAULT_LU_VENDOR "OpenBSD" +#else +#define DEFAULT_LU_VENDOR "FreeBSD" +#endif + +#define DEFAULT_LU_VENDOR_DISK DEFAULT_LU_VENDOR +#define DEFAULT_LU_VENDOR_DVD DEFAULT_LU_VENDOR +#ifndef USE_LU_TAPE_DLT8000 +#define DEFAULT_LU_VENDOR_TAPE DEFAULT_LU_VENDOR +#else +#define DEFAULT_LU_VENDOR_TAPE "QUANTUM" +#endif /* !USE_LU_TAPE_DLT8000 */ +#define DEFAULT_LU_PRODUCT "iSCSI UNIT" +#define DEFAULT_LU_PRODUCT_DISK "iSCSI DISK" +#define DEFAULT_LU_PRODUCT_DVD "iSCSI DVD" +#ifndef USE_LU_TAPE_DLT8000 +#define DEFAULT_LU_PRODUCT_TAPE "iSCSI TAPE" +#else +#define DEFAULT_LU_PRODUCT_TAPE "DLT8000" +#endif /* !USE_LU_TAPE_DLT8000 */ +#define DEFAULT_LU_REVISION "0001" +#define DEFAULT_LU_REVISION_DISK DEFAULT_LU_REVISION +#define DEFAULT_LU_REVISION_DVD DEFAULT_LU_REVISION +#ifndef USE_LU_TAPE_DLT8000 +#define DEFAULT_LU_REVISION_TAPE DEFAULT_LU_REVISION +#else +#define DEFAULT_LU_REVISION_TAPE "C001" +#endif /* !USE_LU_TAPE_DLT8000 */ +#define MAX_INQUIRY_SERIAL 16 + +#define ISTGT_LU_WORK_BLOCK_SIZE (1ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_WORK_ATS_BLOCK_SIZE (1ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_MAX_WRITE_CACHE_SIZE (8ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_MEDIA_SIZE_MIN (1ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_MEDIA_EXTEND_UNIT (256ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_1GB (1ULL * 1024ULL * 1024ULL * 1024ULL) +#define ISTGT_LU_1MB (1ULL * 1024ULL * 1024ULL) + +/* + * CloudByte - additional definitions for multiple luworkers + */ +#define ISTGT_MAX_NUM_LUWORKERS 128 +#define ISTGT_NUM_LUWORKERS_DEFAULT 6 + +typedef enum { + ISTGT_LU_FLAG_MEDIA_READONLY = 0x00000001, + ISTGT_LU_FLAG_MEDIA_AUTOSIZE = 0x00000002, + ISTGT_LU_FLAG_MEDIA_EXTEND = 0x00000010, + ISTGT_LU_FLAG_MEDIA_DYNAMIC = 0x00000020, +} ISTGT_LU_FLAG; + +/* + * Value for max retry attempts by luworkers that get spawned, + * esp for reload (kill -HUP) case to detect lu state in + * RUNNING + */ +#define ISTGT_MAX_LU_RUNNING_STATE_RETRY_COUNT 45 + +typedef enum { + ISTGT_LU_TYPE_NONE = 0, + ISTGT_LU_TYPE_PASS = 1, + ISTGT_LU_TYPE_DISK = 2, + ISTGT_LU_TYPE_DVD = 3, + ISTGT_LU_TYPE_TAPE = 4, +} ISTGT_LU_TYPE; + +typedef enum { + ISTGT_LU_LUN_TYPE_NONE = 0, + ISTGT_LU_LUN_TYPE_DEVICE = 1, + ISTGT_LU_LUN_TYPE_STORAGE = 2, + ISTGT_LU_LUN_TYPE_REMOVABLE = 3, + ISTGT_LU_LUN_TYPE_SLOT = 4, +} ISTGT_LU_LUN_TYPE; + +typedef struct istgt_lu_device_t { + char *file; +} ISTGT_LU_DEVICE; + +typedef struct istgt_lu_storage_t { + int fd; + char *file; + uint64_t size; + uint32_t rsize; + uint32_t rshift; + uint32_t rshiftreal; +} ISTGT_LU_STORAGE; + +typedef struct istgt_lu_removable_t { + int type; + int id; + int flags; + int fd; + char *file; + uint64_t size; +} ISTGT_LU_REMOVABLE; + +typedef struct istgt_lu_slot_t { + int maxslot; + int present[MAX_LU_LUN_SLOT]; + int flags[MAX_LU_LUN_SLOT]; + char *file[MAX_LU_LUN_SLOT]; + uint64_t size[MAX_LU_LUN_SLOT]; +} ISTGT_LU_SLOT; + +typedef struct istgt_lu_lun_t { + int type; + union { + ISTGT_LU_DEVICE device; + ISTGT_LU_STORAGE storage; + ISTGT_LU_REMOVABLE removable; + ISTGT_LU_SLOT slot; + } u; + int rotationrate; + int formfactor; + int opt_tlen; + union { + struct { + int readcache : 1; + int writecache : 1; + int unmap : 1; + int ats : 1; + int xcopy: 1; + int wsame : 1; + int dpofua : 1; + int wzero : 1; + }; + int lunflags; + }; + char *serial; + void *spec; +} ISTGT_LU_LUN; +typedef ISTGT_LU_LUN *ISTGT_LU_LUN_Ptr; + +typedef struct istgt_lu_tsih_t { + int tag; + uint16_t tsih; + char *initiator_port; +} ISTGT_LU_TSIH; + +typedef enum { + AAS_ACTIVE_OPTIMIZED = 0x00, + AAS_ACTIVE_NON_OPTIMIZED = 0x01, + AAS_STANDBY = 0x02, + AAS_UNAVAILABLE = 0x03, + AAS_TRANSITIONING = 0x0F, + + AAS_STATUS_NO = 0x0000, + AAS_STATUS_STPG = 0x0100, + AAS_STATUS_IMPLICIT = 0x0200, +} ISTGT_LU_AAS; + +typedef struct istgt_lu_map_t { + int pg_tag; + int pg_aas; + int ig_tag; +} ISTGT_LU_MAP; + +typedef enum { + ISTGT_UA_NONE = 0X0000, + ISTGT_UA_POWERON = 0X0001, + ISTGT_UA_BUS_RESET = 0X0002, + ISTGT_UA_TARG_RESET = 0X0004, + ISTGT_UA_LUN_RESET = 0X0008, + ISTGT_UA_LUN_CHANGE = 0X0010, + ISTGT_UA_MODE_CHANGE = 0X0020, + ISTGT_UA_LOG_CHANGE = 0X0040, + ISTGT_UA_LVD = 0X0080, + ISTGT_UA_SE = 0X0100, + ISTGT_UA_RES_PREEMPT = 0X0200, + ISTGT_UA_RES_RELEASE = 0X0400, + ISTGT_UA_REG_PREEMPT = 0X0800, + ISTGT_UA_ASYM_ACC_CHANGE = 0X1000, + ISTGT_UA_CAPACITY_CHANGED = 0X2000 +} istgt_ua_type; + +typedef enum { + ISTGT_RSV_NONE = 0X0000, + ISTGT_RSV_READ = 0X0001, +} istgt_rsv_pending; + +typedef struct istgt_lu_disk_nexus { + istgt_ua_type ua_pending; + pthread_mutex_t nexus_mutex; + const char *initiator_port; + TAILQ_ENTRY (istgt_lu_disk_nexus) nexus_next; +}IT_NEXUS; + +typedef struct istgt_lu_t { + int num; + char *name; + char *alias; + + char *inq_vendor; + char *inq_product; + char *inq_revision; + char *inq_serial; + + ISTGT_Ptr istgt; + ISTGT_STATE state; + pthread_mutex_t mutex; + pthread_mutex_t state_mutex; + pthread_mutex_t queue_mutex; + pthread_cond_t queue_cond; + pthread_t luthread[ISTGT_MAX_NUM_LUWORKERS]; + pthread_t schdler_thread; + pthread_t maintenance_thread; + int luworkers; + int luworkersActive; + uint16_t last_tsih; + + int no_auth_chap; + int auth_chap; + int auth_chap_mutual; + int auth_group; + int header_digest; + int data_digest; + + int MaxOutstandingR2T; + int DefaultTime2Wait; + int DefaultTime2Retain; + int FirstBurstLength; + int MaxBurstLength; + int MaxRecvDataSegmentLength; + int InitialR2T; + int ImmediateData; + int DataPDUInOrder; + int DataSequenceInOrder; + int ErrorRecoveryLevel; + + int type; + int online; + int readonly; + int blocklen; + int recordsize; + int rshift; + int queue_depth; + int limit_q_size; + int queue_check; + + int maxlun; + ISTGT_LU_LUN lun[MAX_LU_LUN]; + int maxtsih; + ISTGT_LU_TSIH tsih[MAX_LU_TSIH]; + int maxmap; + ISTGT_LU_MAP map[MAX_LU_MAP]; + int conns; + +} ISTGT_LU; +typedef ISTGT_LU *ISTGT_LU_Ptr; + +typedef enum { + ISTGT_TAG_UNTAGGED, + ISTGT_TAG_SIMPLE, + ISTGT_TAG_ORDERED, + ISTGT_TAG_HEAD_OF_QUEUE, + ISTGT_TAG_ACA +} istgt_tag_type; + +#define _PSZ 16 + +enum { +ISTGT_ADD_TO_MAINT = 0x00000001, +ISTGT_ADD_TO_CMD = 0x00000002, +ISTGT_ADD_TO_BLOCKED_CMD = 0x00000004, +ISTGT_ADD_TO_BLOCKED_MAINT = 0x00000008, +ISTGT_UNBLOCKED = 0x00000010, +ISTGT_MAINT_WORKER_PICKED = 0x00000020, +ISTGT_SCHEDULED = 0x00000040, +ISTGT_WORKER_PICKED = 0x00000080, +ISTGT_DISK_EXEC = 0x00000100, +ISTGT_COMPLETED_EXEC = 0x00000200, +ISTGT_RESULT_Q_ENQUEUED = 0x00000400, +ISTGT_RESULT_Q_DEQUEUED = 0x00000800 +}; + +typedef struct istgt_lu_cmd_t { + struct iscsi_pdu_t *pdu; + ISTGT_LU_Ptr lu; + + uint64_t lba; + uint32_t lblen; + uint8_t cdb0; + uint8_t infdx; + union { + struct { + uint16_t dpo : 1; + uint16_t fua : 1; + uint16_t fua_nv : 1; + uint16_t bytchk : 1; + uint16_t anchor : 1; + uint16_t unmap : 1; + uint16_t pbdata : 1; + uint16_t lbdata : 1; + uint16_t sync_nv: 1; + uint16_t immed : 1; + uint16_t wprot : 3; + }; + uint16_t cdbflags; + }; + union { + char info[8]; + uint64_t infcpy; + }; + + int I_bit; + int F_bit; + int R_bit; + int W_bit; + istgt_tag_type Attr_bit; + uint64_t lun; + uint32_t task_tag; + uint32_t flags; + uint32_t transfer_len; + uint32_t CmdSN; + uint8_t *cdb; + + uint64_t iobufsize; + int iobufindx; + struct iovec iobuf[20]; + //int iobufoff[20]; int iobufsize[20]; uint8_t *iobuf[20]; + + uint8_t *data; + size_t data_len; + size_t alloc_len; + + int status; + uint8_t *sense_data; + size_t sense_data_len; + size_t sense_alloc_len; + + int lunum; + + struct timespec times[_PSZ]; + struct timespec tdiff[_PSZ]; + char caller[_PSZ]; + uint16_t line[_PSZ]; + uint8_t _andx; + uint8_t _lst; + uint8_t _roll_cnt; + uint8_t connGone; + uint8_t aborted; + uint8_t release_aborted; +} ISTGT_LU_CMD; +typedef ISTGT_LU_CMD *ISTGT_LU_CMD_Ptr; + +void timediff(ISTGT_LU_CMD_Ptr p, char ch, uint16_t line); + +typedef enum { + __TUR = 0, // "TEST_UNIT_READY" + __RQSNS, // "REQ_SENSE" + __FMT, // "FMT_UNIT" + __RBL, // "READ_BLOCK_LIMITS" + __RD6, // "READ6" + __WR6, // "WRITE6" + __INQ, // "INQUIRY" + __MSEL, // "MODE_SELECT" + __RSV6, // "RESERVE6" + __REL6, // "RELEASE6" + __MSN6, // "MODE SENSE6" + __START, // "START STOP UNIT" + __RCAP10, // "READCAP10" + __RD10, // "READ10" + __WR10, // "WRITE10" + __WV10, // "WRITE_AND_VERIFY10" + __PREFTCH10,// "PREFETCH10" + __SYC10, // "SYNC_CACHE10" + __RDDEF, // "READ_DEFECT_DATA" + __WBF, // "WRITE_BUFFER" + __WS10, // "WRITE_SAME10" + __UNMAP, // "UNMAP" + __XDW, // "XDxx" + __MSEL10, // "MODE_SELECT10" + __RSV10, // "RESERVE10" + __REL10, // "RELEASE10" + __MSN10, // "MODE_SENSE10" + __PRIN, // "PR_IN" + __PROUT, // "PR_OUT" + __XCPY, // "XCOPY" + __RCVCPY, // "RECV_COPY_RESULTS" + __RD16, // "READ16" + __ATS, // "ATS" + __WR16, // "WRITE16" + __WV16, // "WRITE_AND_VERIFY16" + __SYC16, // "SYNC_CACHE16" + __WS16, // "WRITE_SAME16" + __RDCAP, // "RDCAP_SAIN16" + __RLUN, // "REPORT LUNS" + __M_IN, // "MAINTENANCE_IN" + __RD12, // "READ12" + __WR12, // "WRITE12" + __WRV12, // "WRITE_VERIFY12" + __ISMx, // "ISMXX" + SCSI_ARYSZ, + __UNK = SCSI_ARYSZ +} scsi_stat_idx; + +typedef enum { + NOPOUT = 0, SCSI, TASK, LOGIN, TXT, DATAOUT, LOGOUT, SNACK, VEN_1C, VEN_1D, VEN_1E, + NOPIN, SCSI_RSP, TASK_RSP, LOGIN_RSP, TXT_RSP, DATAIN, LOGOUT_RSP, R2T, ASYNC, VEN_3C, VEN_3D, VEN_3E, REJECT, + ISCSI_ARYSZ, + UNDEF = ISCSI_ARYSZ +} isciOpInd; + +typedef struct _istat { + uint8_t opcode; + uint32_t pdu_read; + uint32_t pdu_sent; +} _verb_istat; + +typedef struct _stat { + uint8_t opcode; + uint32_t req_start; + uint32_t req_finish; + //uint32_t req_inflight; + //uint64_t req_avgtime; +} _verb_stat; + +typedef enum { + ISTGT_SERIDX_TUR = 0, + ISTGT_SERIDX_READ, + ISTGT_SERIDX_WRITE, + ISTGT_SERIDX_UNMAP, + ISTGT_SERIDX_MD_SNS, + ISTGT_SERIDX_MD_SEL, + ISTGT_SERIDX_RQ_SNS, + ISTGT_SERIDX_INQ, + ISTGT_SERIDX_RD_CAP, + ISTGT_SERIDX_RESV, + ISTGT_SERIDX_REL, + ISTGT_SERIDX_LOG_SNS, + ISTGT_SERIDX_FORMAT, + ISTGT_SERIDX_START, + ISTGT_SERIDX_PRES_IN, + ISTGT_SERIDX_PRES_OUT, + ISTGT_SERIDX_MAIN_IN, + ISTGT_SERIDX_COUNT, + ISTGT_SERIDX_INVLD = ISTGT_SERIDX_COUNT +} istgt_seridx; + +typedef enum { + ISTGT_CMD_FLAG_NONE = 0x0000, + ISTGT_CMD_FLAG_NO_SENSE = 0x0010, + ISTGT_CMD_FLAG_OK_ON_ALL_LUNS = 0x0020, + ISTGT_CMD_FLAG_ALLOW_ON_RESV = 0x0040, + ISTGT_CMD_FLAG_OK_ON_PROC = 0x0100, + ISTGT_CMD_FLAG_OK_ON_SLUN = 0x0200, + ISTGT_CMD_FLAG_OK_ON_BOTH = 0x0300, + ISTGT_CMD_FLAG_OK_ON_STOPPED = 0x0400, + ISTGT_CMD_FLAG_OK_ON_INOPERABLE = 0x0800, + ISTGT_CMD_FLAG_OK_ON_OFFLINE = 0x1000, + ISTGT_CMD_FLAG_OK_ON_SECONDARY = 0x2000, + ISTGT_CMD_FLAG_ALLOW_ON_PR_RESV = 0x4000 +} istgt_cmd_flags; + +/* This may not be needed for control but looking at ctl + * operational state we will decide on if we need to use this + * or not + */ + +typedef enum { + ISTGT_FLAG_NONE = 0x00000000, /* no flags */ + ISTGT_FLAG_DATA_IN = 0x00000001, /* DATA IN */ + ISTGT_FLAG_DATA_OUT = 0x00000002, /* DATA OUT */ + ISTGT_FLAG_DATA_NONE = 0x00000003, /* no data */ + ISTGT_FLAG_DATA_MASK = 0x00000003, + ISTGT_FLAG_KDPTR_SGLIST = 0x00000008, /* kern_data_ptr is S/G list*/ + ISTGT_FLAG_EDPTR_SGLIST = 0x00000010, /* ext_data_ptr is S/G list */ + ISTGT_FLAG_DO_AUTOSENSE = 0x00000020, /* grab sense info */ + ISTGT_FLAG_USER_REQ = 0x00000040, /* request came from userland */ + ISTGT_FLAG_CONTROL_DEV = 0x00000080, /* processor device */ + ISTGT_FLAG_ALLOCATED = 0x00000100, /* data space allocated */ + ISTGT_FLAG_BLOCKED = 0x00000200, /* on the blocked queue */ + ISTGT_FLAG_ABORT = 0x00000800, /* this I/O should be aborted */ + ISTGT_FLAG_DMA_INPROG = 0x00001000, /* DMA in progress */ + ISTGT_FLAG_NO_DATASYNC = 0x00002000, /* don't cache flush data */ + ISTGT_FLAG_DELAY_DONE = 0x00004000, /* delay injection done */ + ISTGT_FLAG_INT_COPY = 0x00008000, /* internal copy, no done call*/ + ISTGT_FLAG_SENT_2OTHER_SC = 0x00010000, + ISTGT_FLAG_FROM_OTHER_SC = 0x00020000, + ISTGT_FLAG_IS_WAS_ON_RTR = 0x00040000, /* Don't rerun cmd on failover*/ + ISTGT_FLAG_BUS_ADDR = 0x00080000, /* ctl_sglist contains BUS + addresses, not virtual ones*/ + ISTGT_FLAG_IO_CONT = 0x00100000, /* Continue I/O instead of + completing */ + ISTGT_FLAG_AUTO_MIRROR = 0x00200000, /* Automatically use memory + from the RC cache mirrored + address area. */ +#if 0 + ISTGT_FLAG_ALREADY_DONE = 0x00200000 /* I/O already completed */ +#endif + ISTGT_FLAG_NO_DATAMOVE = 0x00400000, + ISTGT_FLAG_DMA_QUEUED = 0x00800000, /* DMA queued but not started*/ + ISTGT_FLAG_STATUS_QUEUED = 0x01000000, /* Status queued but not sent*/ + + ISTGT_FLAG_REDIR_DONE = 0x02000000, /* Redirection has already + been done. */ + ISTGT_FLAG_FAILOVER = 0x04000000, /* Killed by a failover */ + ISTGT_FLAG_IO_ACTIVE = 0x08000000, /* I/O active on this SC */ + ISTGT_FLAG_RDMA_MASK = ISTGT_FLAG_NO_DATASYNC | ISTGT_FLAG_BUS_ADDR | + ISTGT_FLAG_AUTO_MIRROR | ISTGT_FLAG_REDIR_DONE + /* Flags we care about for + remote DMA */ +} istgt_io_flags; + +struct istgt_cmd_entry { + //istgt_opfunc *execute; /* NOT inuse */ + istgt_seridx seridx; + uint64_t flags; /* istgt_io_flags + istgt cmd flags */ + scsi_stat_idx statidx; +// istgt_lun_error_pattern pattern; +}; + +enum { + ISTGT_LU_TASK_RESULT_IMMEDIATE = 0, + ISTGT_LU_TASK_RESULT_QUEUE_OK = 1, + ISTGT_LU_TASK_RESULT_QUEUE_FULL = 2, +} ISTGT_LU_TASK_RESULT; + +enum { + ISTGT_LU_TASK_RESPONSE = 0, + ISTGT_LU_TASK_REQPDU = 1, + ISTGT_LU_TASK_REQUPDPDU = 2, +} ISTGT_LU_TASK_TYPE; + +typedef enum { + ISTGT_SER_BLOCK, + ISTGT_SER_EXTENT, + ISTGT_SER_PASS, + ISTGT_SER_SKIP +} istgt_serialize_action; + +typedef enum { + ISTGT_TASK_BLOCK, + ISTGT_TASK_OVERLAP, + ISTGT_TASK_OVERLAP_TAG, + ISTGT_TASK_BLOCK_SUSPECT, + ISTGT_TASK_PASS, + ISTGT_TASK_SKIP, + ISTGT_TASK_ERROR +} istgt_task_action; + +typedef struct istgt_lu_task_t { + uint16_t type; + uint16_t cdb0; + uint32_t lblen; + uint64_t lba; + uint64_t lbE; + + uint16_t in_plen; + char in_port[MAX_INITIATOR_NAME]; + + struct istgt_conn_t *conn; + ISTGT_LU_CMD lu_cmd; + int lun; + pthread_t thread; + int use_cond; + pthread_mutex_t trans_mutex; + pthread_cond_t trans_cond; + pthread_cond_t exec_cond; + + int condwait; + + int dup_iobuf; + size_t alloc_len; + + int offset; + int req_execute; + int req_transfer_out; + int error; + int abort; + int execute; + int complete; + int lock; + void *complete_queue_ptr;//Pointer to the task in Complete queue + ISTGT_QUEUE_Ptr blocked_by;// Pointer to the last task in complete queue blocking the current task + + int flags; +} ISTGT_LU_TASK; +typedef ISTGT_LU_TASK *ISTGT_LU_TASK_Ptr; + +/* lu_disk.c */ +typedef struct istgt_lu_pr_key_t { + uint64_t key; + + /* transport IDs */ + char *registered_initiator_port; + char *registered_target_port; + /* PERSISTENT RESERVE OUT received from */ + int pg_idx; /* relative target port */ + int pg_tag; /* target port group */ + + int ninitiator_ports; + char **initiator_ports; + int all_tpg; +} ISTGT_LU_PR_KEY; + +typedef enum { + ISTGT_LUN_ONLINE, + ISTGT_LUN_BUSY +}istgt_lun_state; + +typedef enum { + ISTGT_LUN_OPEN_PENDING, /* ask one worker to start opening the file */ + ISTGT_LUN_OPEN_INPROGRESS, /* one worker is in the process of opening */ + ISTGT_LUN_OPEN, + ISTGT_LUN_CLOSE_PENDING, /* one worker has to pick and start the spec sync and close */ + ISTGT_LUN_CLOSE_INPROGRESS, /*one worker has already started the close */ + ISTGT_LUN_CLOSE, + ISTGT_LUN_NOTYET +}istgt_lun_ex_state; + +struct timeavgs +{ + unsigned int count; + unsigned long tot_sec; + unsigned long tot_nsec; +}; + +struct IO_info +{ + struct timespec total_time; + struct timespec tdiff[_PSZ]; + char caller[_PSZ]; + uint8_t _andx; + uint64_t lba; + uint64_t lblen; +}; + +struct IO_types +{ + struct IO_info write; + struct IO_info read; + struct IO_info cmp_n_write; + struct IO_info unmp; + struct IO_info write_same; +}; + +struct istgt_lu_disk_t; + +struct luworker_exit_args { + struct istgt_lu_disk_t *spec; + int workerid; + ISTGT_LU_TASK_Ptr lu_task; +}; + +#define HOLD_SCHEDULER 0x1 +#define WRITE_INFLIGHT_ISCSI 0x2 +#define WRITE_INFLIGHT_ONDISK 0x4 +#define READ_INFLIGHT_ISCSI 0x8 +#define READ_INFLIGHT_ONDISK 0x10 +#define R2T_TASK_BEFORE_WAIT 0x20 +#define R2T_TASK_AFTER_WAIT 0x40 +#define SEND_R2T 0x80 +#define SEND_TASK_RSP 0x100 + +typedef struct istgt_lu_disk_t { + ISTGT_LU_Ptr lu; + int num; + int lun; + int inflight; + int persist; + int fd; + const char *file; + const char *disktype; + void *exspec; + uint64_t fsize; + uint64_t foffset; + uint64_t size; + uint64_t blocklen; + uint64_t blockcnt; + uint32_t rsize; + uint32_t rshift; + uint32_t rshiftreal; + uint32_t max_unmap_sectors; + struct IO_types IO_size[10]; + + /* modify lun */ + int dofake; + pthread_t diskmod_thr; + +#ifdef HAVE_UUID_H + uuid_t uuid; +#endif /* HAVE_UUID_H */ + + uint32_t lb_per_rec; + uint16_t opt_tlen; + + /* thin provisioning */ + union { + struct { + uint16_t readcache : 1; + uint16_t writecache : 1; + uint16_t unmap : 1; + uint16_t ats : 1; + uint16_t xcopy : 1; + uint16_t wsame : 1; + uint16_t dpofua : 1; + uint16_t wzero : 1; + uint16_t delay_reserve : 1; + uint16_t delay_release : 1; + uint16_t exit_lu_worker : 1; + }; + uint16_t lunflags; + }; + + uint32_t error_inject; + int32_t inject_cnt; + + /* for ats */ + uint8_t *watsbuf; + + /* for clone */ + pthread_mutex_t clone_mutex; + + int luworkers; //we have one-to-one mapping between LU and LUN (spec) + int luworkersActive; + int queue_depth; + ISTGT_LU_TASK_Ptr inflight_io[ISTGT_MAX_NUM_LUWORKERS]; + pthread_cond_t cmd_queue_cond; + int disk_modify_work_pending; + pthread_cond_t maint_cmd_queue_cond; + ISTGT_QUEUE maint_cmd_queue; + ISTGT_QUEUE maint_blocked_queue; + ISTGT_QUEUE cmd_queue; + ISTGT_QUEUE blocked_queue; + /*Queue containing all the tasks. Instead of going to separate + queues (Cmd Queue, blocked queue, maint_cmd_que, maint_blocked_queue, + inflight)to check for blockage, we will check it in just this queue.*/ + ISTGT_QUEUE complete_queue; + pthread_mutex_t complete_queue_mutex; + + pthread_mutex_t schdler_mutex; + pthread_mutex_t sleep_mutex; + pthread_cond_t schdler_cond; + uint8_t schdler_waiting; + uint8_t schdler_cmd_waiting; + uint8_t maint_thread_waiting; + uint8_t error_count; + pthread_mutex_t luworker_mutex[ISTGT_MAX_NUM_LUWORKERS]; + pthread_cond_t luworker_cond[ISTGT_MAX_NUM_LUWORKERS]; + uint8_t luworker_waiting[ISTGT_MAX_NUM_LUWORKERS]; + uint32_t lu_free_matrix[(ISTGT_MAX_NUM_LUWORKERS/32) + 1]; + + pthread_mutex_t lu_tmf_mutex[ISTGT_MAX_NUM_LUWORKERS]; + pthread_cond_t lu_tmf_cond[ISTGT_MAX_NUM_LUWORKERS]; + uint8_t lu_tmf_wait[ISTGT_MAX_NUM_LUWORKERS]; + + pthread_mutex_t wait_lu_task_mutex; + ISTGT_LU_TASK_Ptr wait_lu_task[ISTGT_MAX_NUM_LUWORKERS]; + + struct luworker_exit_args luworker_exit_arg[ISTGT_MAX_NUM_LUWORKERS]; + pthread_mutex_t pr_rsv_mutex; + /* PERSISTENT RESERVE */ + int npr_keys; + ISTGT_LU_PR_KEY pr_keys[MAX_LU_RESERVE]; + uint32_t pr_generation; + + char *rsv_port; + uint64_t rsv_key; + int rsv_scope; + int rsv_type; + + istgt_rsv_pending rsv_pending; + + TAILQ_HEAD (, istgt_lu_disk_nexus) nexus; + + int spc2_reserved; + + /* SCSI sense code */ + volatile int sense; + + pthread_mutex_t state_mutex; + int ludsk_ref; + int open_waiting4close; + int close_waiting4open; + struct timespec close_started; + struct timespec open_started; + istgt_lun_ex_state ex_state; + istgt_lun_state state; + struct timeavgs avgs[32]; + int do_avg; + int fderr; + int fderrno; + uint8_t percent_count; + uint8_t percent_val[32]; + uint8_t percent_latency[32]; + + /* entry */ + int (*open)(struct istgt_lu_disk_t *spec, int flags, int mode); + int (*close)(struct istgt_lu_disk_t *spec); + int64_t (*seek)(struct istgt_lu_disk_t *spec, uint64_t offset); + + int64_t (*sync)(struct istgt_lu_disk_t *spec, uint64_t offset, uint64_t nbytes); + int (*allocate)(struct istgt_lu_disk_t *spec); + int (*setcache)(struct istgt_lu_disk_t *spec); +} ISTGT_LU_DISK; + +#ifdef CB_COMPILE +typedef struct scsi_pr_key SCSI_PR_KEY; +typedef struct scsi_pr_data SCSI_PR_DATA; +#else +/* To store Persistent Registrations */ +typedef struct scsi_pr_key { + uint64_t key; + char registered_initiator_port[256]; + char registered_target_port[256]; + int pg_idx; + int pg_tag; + int all_tpg; +} SCSI_PR_KEY; + +/* To store Persistent Reservation */ +typedef struct scsi_pr_data { + int npr_keys; + int rsv_scope; + int rsv_type; + uint32_t pr_generation; + uint64_t rsv_key; + char rsv_port[256]; + struct scsi_pr_key keys[MAX_LU_ZAP_RESERVE]; +} SCSI_PR_DATA; +#endif + +void *timerfn(void *); +extern ISTGT_QUEUE closedconns; + + +typedef enum { + ACTION_CLOSE, + ACTION_OPEN +} istgt_action; + +int istgt_lu_disk_signal_action(ISTGT_LU_Ptr lu, int i, struct timespec *now, istgt_action act); +int istgt_lu_disk_close(ISTGT_LU_Ptr lu, int i); +int istgt_lu_disk_open(ISTGT_LU_Ptr lu, int i); +int istgt_lu_disk_post_open(ISTGT_LU_DISK *spec); + +extern struct istgt_cmd_entry istgt_cmd_table[] ; +extern istgt_serialize_action istgt_serialize_table[ISTGT_SERIDX_COUNT + 1][ISTGT_SERIDX_COUNT + 1]; + +int +istgt_lu_disk_update_raw(ISTGT_LU_Ptr lu, int i, int dofake); + +int istgt_lu_print_q(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_print_reservation(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_close_raw(ISTGT_LU_DISK *spec); +int istgt_lu_disk_get_reservation(ISTGT_LU_DISK *spec); + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#endif /* ISTGT_LU_H */ diff --git a/src/istgt_lu_ctl.c b/src/istgt_lu_ctl.c new file mode 100644 index 00000000..aa4fab60 --- /dev/null +++ b/src/istgt_lu_ctl.c @@ -0,0 +1,3474 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include +#include + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_md5.h" +#include "istgt_lu.h" +#include "istgt_iscsi.h" +#include "istgt_proto.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#define TIMEOUT_RW 60 +#define MAX_LINEBUF 4096 +//#define MAX_LINEBUF 8192 + +typedef struct istgt_uctl_t { + int id; + + ISTGT_Ptr istgt; + PORTAL portal; + int sock; + pthread_t thread; + + int family; + char caddr[MAX_ADDRBUF]; + char saddr[MAX_ADDRBUF]; + uint32_t iport; + uint32_t iaddr; + + ISTGT_CHAP_AUTH auth; + int authenticated; + + int timeout; + int auth_group; + int no_auth; + int req_auth; + int req_mutual; + + char *mediadirectory; + + int recvtmpsize; + int recvtmpcnt; + int recvtmpidx; + int recvbufsize; + int sendbufsize; + int worksize; + char recvtmp[MAX_LINEBUF]; + char recvbuf[MAX_LINEBUF]; + char sendbuf[MAX_LINEBUF]; + char work[MAX_LINEBUF]; + char *cmd; + char *arg; +} UCTL; +typedef UCTL *UCTL_Ptr; + +typedef enum { + UCTL_CMD_OK = 0, + UCTL_CMD_ERR = 1, + UCTL_CMD_EOF = 2, + UCTL_CMD_QUIT = 3, + UCTL_CMD_DISCON = 4, +} UCTL_CMD_STATUS; + +#define ARGS_DELIM " \t" + +static int +istgt_uctl_readline(UCTL_Ptr uctl) +{ + ssize_t total; + + total = istgt_readline_socket(uctl->sock, uctl->recvbuf, uctl->recvbufsize, + uctl->recvtmp, uctl->recvtmpsize, + &uctl->recvtmpidx, &uctl->recvtmpcnt, + uctl->timeout); + if (total < 0) { + return UCTL_CMD_DISCON; + } + if (total == 0) { + return UCTL_CMD_EOF; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_writeline(UCTL_Ptr uctl) +{ + ssize_t total; + ssize_t expect; + + expect = strlen(uctl->sendbuf); + total = istgt_writeline_socket(uctl->sock, uctl->sendbuf, uctl->timeout); + if (total < 0) { + return UCTL_CMD_DISCON; + } + if (total != expect) { + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int istgt_uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3))); + +static int +istgt_uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) +{ + va_list ap; + int rc; + + va_start(ap, format); + rc = vsnprintf(uctl->sendbuf, uctl->sendbufsize, format, ap); + va_end(ap); + return rc; +} + +static int +istgt_uctl_get_media_present(ISTGT_LU_Ptr lu __attribute__((__unused__)), int lun __attribute__((__unused__))) +{ + return 0; +} + +static int +istgt_uctl_get_media_lock(ISTGT_LU_Ptr lu __attribute__((__unused__)), int lun __attribute__((__unused__))) +{ + return 0; +} + +static int +istgt_uctl_get_authinfo(UCTL_Ptr uctl, const char *authuser) +{ + char *authfile = NULL; + int ag_tag; + int rc; + + ag_tag = uctl->auth_group; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ag_tag=%d\n", ag_tag); + + MTX_LOCK(&uctl->istgt->mutex); + authfile = xstrdup(uctl->istgt->authfile); + MTX_UNLOCK(&uctl->istgt->mutex); + + rc = istgt_chap_get_authinfo(&uctl->auth, authfile, authuser, ag_tag); + if (rc < 0) { + ISTGT_ERRLOG("chap_get_authinfo() failed\n"); + xfree(authfile); + return -1; + } + xfree(authfile); + return 0; +} + +static int +istgt_uctl_cmd_auth(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *label; + char *chap_a; + char *chap_i; + char *chap_c; + char *chap_n; + char *chap_r; + int rc; + + arg = uctl->arg; + label = strsepq(&arg, delim); + + if (label == NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (strcasecmp(label, "CHAP_A") == 0) { + if (uctl->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_A) { + istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n"); + error_return: + uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A; + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + chap_a = strsepq(&arg, delim); + if (chap_a == NULL || strcasecmp(chap_a, "5") != 0) { + istgt_uctl_snprintf(uctl, "ERR invalid algorithm\n"); + goto error_return; + } + + /* Identifier is one octet */ + istgt_gen_random(uctl->auth.chap_id, 1); + /* Challenge Value is a variable stream of octets */ + /* (binary length MUST not exceed 1024 bytes) */ + uctl->auth.chap_challenge_len = ISTGT_CHAP_CHALLENGE_LEN; + istgt_gen_random(uctl->auth.chap_challenge, + uctl->auth.chap_challenge_len); + + istgt_bin2hex(uctl->work, uctl->worksize, + uctl->auth.chap_challenge, + uctl->auth.chap_challenge_len); + + istgt_uctl_snprintf(uctl, "%s CHAP_IC %d %s\n", + uctl->cmd, (int) uctl->auth.chap_id[0], + uctl->work); + + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_NR; + /* 3-way handshake */ + return UCTL_CMD_OK; + } else if (strcasecmp(label, "CHAP_NR") == 0) { + uint8_t resmd5[ISTGT_MD5DIGEST_LEN]; + uint8_t tgtmd5[ISTGT_MD5DIGEST_LEN]; + ISTGT_MD5CTX md5ctx; + + if (uctl->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_NR) { + istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n"); + goto error_return; + } + + chap_n = strsepq(&arg, delim); + chap_r = strsepq(&arg, delim); + if (chap_n == NULL || chap_r == NULL) { + istgt_uctl_snprintf(uctl, "ERR no response\n"); + goto error_return; + } + //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "N=%s, R=%s\n", chap_n, chap_r); + + rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, chap_r); + if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) { + istgt_uctl_snprintf(uctl, "ERR response format error\n"); + goto error_return; + } + + rc = istgt_uctl_get_authinfo(uctl, chap_n); + if (rc < 0) { + ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n); + istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n"); + goto error_return; + } + if (uctl->auth.user == NULL || uctl->auth.secret == NULL) { + ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n); + istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n"); + goto error_return; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, uctl->auth.chap_id, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, uctl->auth.secret, + strlen(uctl->auth.secret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, uctl->auth.chap_challenge, + uctl->auth.chap_challenge_len); + /* tgtmd5 is expecting Response Value */ + istgt_md5final(tgtmd5, &md5ctx); + + /* compare MD5 digest */ + if (memcmp(tgtmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) { + /* not match */ + ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n); + istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n"); + goto error_return; + } + /* OK client's secret */ + uctl->authenticated = 1; + + /* mutual CHAP? */ + chap_i = strsepq(&arg, delim); + chap_c = strsepq(&arg, delim); + if (chap_i != NULL && chap_c != NULL) { + /* Identifier */ + uctl->auth.chap_mid[0] = (uint8_t) strtol(chap_i, NULL, 10); + /* Challenge Value */ + rc = istgt_hex2bin(uctl->auth.chap_mchallenge, + ISTGT_CHAP_CHALLENGE_LEN, chap_c); + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR challenge format error\n"); + goto error_return; + } + uctl->auth.chap_mchallenge_len = rc; + + if (uctl->auth.muser == NULL || uctl->auth.msecret == NULL) { + ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n); + istgt_uctl_snprintf(uctl, + "ERR auth user or secret is missing\n"); + goto error_return; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, uctl->auth.chap_mid, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, uctl->auth.msecret, + strlen(uctl->auth.msecret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge, + uctl->auth.chap_mchallenge_len); + /* tgtmd5 is Response Value */ + istgt_md5final(tgtmd5, &md5ctx); + + istgt_bin2hex(uctl->work, uctl->worksize, + tgtmd5, ISTGT_MD5DIGEST_LEN); + + /* send NR for mutual CHAP */ + istgt_uctl_snprintf(uctl, "%s CHAP_NR \"%s\" %s\n", + uctl->cmd, + uctl->auth.muser, + uctl->work); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } else { + /* not mutual */ + if (uctl->req_mutual) { + ISTGT_ERRLOG("required mutual CHAP\n"); + istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n"); + goto error_return; + } + } + + uctl->auth.chap_phase = ISTGT_CHAP_PHASE_END; + } else { + istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n"); + goto error_return; + } + + /* auth succeeded (but mutual may fail) */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_quit(UCTL_Ptr uctl) +{ + int rc; + + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_QUIT; +} + +static int +istgt_uctl_cmd_noop(UCTL_Ptr uctl) +{ + int rc; + + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +extern char istgtvers[80]; +static int +istgt_uctl_cmd_version(UCTL_Ptr uctl) +{ + int rc; + + istgt_uctl_snprintf(uctl, "%s %s\n", uctl->cmd, istgtvers); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* version succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_sync(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun == NULL) { + lun_i = 0; + } + else { + lun_i = (int) strtol(lun, NULL, 10); + } + + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + if (lu->type == ISTGT_LU_TYPE_DISK) { + MTX_LOCK(&lu->mutex); + rc = istgt_lu_disk_sync_reservation(lu, lun_i); + MTX_UNLOCK(&lu->mutex); + if(rc < 0) + istgt_uctl_snprintf(uctl, "ERR in sync cmd execution\n"); + } + else { + istgt_uctl_snprintf(uctl, "ERR sync_rsv \n"); + rc = -1; + } + + if (rc < 0) { + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + /* logging event */ + ISTGT_NOTICELOG("Unit Rsv_Persist %s lun%d\n", iqn, lun_i); + /* Persist succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} +static int +istgt_uctl_cmd_set(UCTL_Ptr uctl) +{ + ISTGT_Ptr istgt = uctl->istgt; + ISTGT_LU_Ptr lu = NULL; + ISTGT_LU_DISK *spec = NULL, *spec1 = NULL;; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int i = 0; + int rc = 0; + uint8_t val1, val2; + + int setopt = 0; + int setval = 0, j, tot = 0; + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + setopt = atoi(strsepq(&arg, delim)); + setval = atoi(strsepq(&arg, delim)); + ISTGT_LOG("%s %s %d %d %s\n", iqn, lun, setopt, setval, arg); + + if (iqn == NULL || (arg != NULL && setopt != 15)) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + goto error_return; + } + + if(setopt == 0) { + istgt_uctl_snprintf(uctl, "ERR no setopt\n"); + goto error_return; + } + if(setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d for opt %d\n", setval, setopt); + goto error_return; + } + if(strcmp(iqn, "ALL")) { + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + spec = lu->lun[0].spec; + } + + switch(setopt) { + case 1: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + ISTGT_LOG("send_abrt_resp %d->%d\n", send_abrt_resp, setval); + send_abrt_resp = setval; + break; + case 2: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + ISTGT_LOG("abort_result_queue %d->%d\n", abort_result_queue, setval); + abort_result_queue = setval; + break; + case 3: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + ISTGT_LOG("wait_inflights %d->%d\n" , wait_inflights, setval); + wait_inflights = setval; + break; + case 4: + if(setval < 1) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->max_unmap_sectors = setval; + } + ISTGT_LOG("ALL->max_unmap_sectors ->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->max_unmap_sectors %d->%d\n", iqn, spec->max_unmap_sectors, setval); + spec->max_unmap_sectors = setval; + break; + case 5: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + ISTGT_LOG("clear_resv %d->%d\n" , clear_resv, setval); + clear_resv = setval; + break; + case 6: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->ats = setval; + } + ISTGT_LOG("ALL->ats ->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->ats %d->%d\n", iqn, spec->ats, setval); + spec->ats = setval; + break; + case 7: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->xcopy = setval; + } + ISTGT_LOG("ALL->xcopy ->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->xcopy %d->%d\n", iqn, spec->xcopy, setval); + spec->xcopy = setval; + break; + case 8: + if(setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + istgt->logical_unit[i]->limit_q_size = setval; + } + ISTGT_LOG("ALL->limit_q_size ->%d\n", setval); + break; + } else { + ISTGT_LOG("%s->limit_q_size %d->%d\n", iqn, lu->limit_q_size, setval); + lu->limit_q_size = setval; + } + break; + case 9: + if(setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d for 9\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->delay_reserve = setval; + } + ISTGT_LOG("ALL->delay_reserve ->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->delay_reserve %d->%d\n", iqn, spec->delay_reserve, setval); + spec->delay_reserve = setval; + break; + case 10: + if(setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d for 9\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->delay_release = setval; + } + ISTGT_LOG("ALL->delay_release ->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->delay_release %d->%d\n", iqn, spec->delay_release, setval); + spec->delay_release = setval; + break; + case 11: + if(setval > 1 || setval < 0) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + ISTGT_LOG("abort_release %d->%d\n" , abort_release, setval); + abort_release = setval; + break; + case 12: + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->error_inject = setval; + } + ISTGT_LOG("ALL->error_inject->0x%x\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->error_inject 0x%x->0x%x\n", iqn, spec->error_inject, setval); + spec->error_inject = setval; + break; + case 13: + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->inject_cnt = setval; + } + ISTGT_LOG("ALL->inject_cnt->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->inject_cnt %d->%d\n", iqn, spec->inject_cnt, setval); + spec->inject_cnt = setval; + break; + case 14: + if(setval > 1) + { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + if(!strcmp(iqn, "ALL")) { + for (i = 1; i <= istgt->nlogical_unit; i++) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + spec->exit_lu_worker = setval; + } + ISTGT_LOG("ALL->exit_lu_worker->%d\n", setval); + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + ISTGT_LOG("%s->exit_lu_worker %d->%d\n", iqn, spec->exit_lu_worker, setval); + spec->exit_lu_worker = setval; + break; + case 15: + if(setval < 2 || setval%2 != 0) + { + istgt_uctl_snprintf(uctl, "ERR invalid parameter value %d\n", setval); + goto error_return; + } + spec->percent_count = 0; + sleep(1); + if(!strcmp(iqn, "ALL")) { + spec = (ISTGT_LU_DISK *)istgt->logical_unit[1]->lun[0].spec; + + tot = 0; + for(j=0;jpercent_val[j>>1] = val1; + spec->percent_latency[j>>1] = val2; + ISTGT_LOG("%d %d\n", val1, val2); + } + + if(tot != 100) + { + istgt_uctl_snprintf(uctl, "ERR in tot %d percentage\n", tot); + goto error_return; + } + spec->percent_count = (j>>1); + + for (i = 2; i <= istgt->nlogical_unit; i++) { + spec1 = (ISTGT_LU_DISK *)istgt->logical_unit[i]->lun[0].spec; + for(j=0;jpercent_val[j>>1] = spec->percent_val[j>>1]; + spec1->percent_latency[j>>1] = spec->percent_latency[j>>1]; + } + spec1->percent_count = (j>>1); + } + break; + } + if(spec==NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameter ALL\n"); + goto error_return; + } + tot = 0; + for(j=0;jpercent_val[j>>1] = val1; + spec->percent_latency[j>>1] = val2; + ISTGT_LOG("%d %d\n", val1, val2); + } + + if(tot != 100) + { + istgt_uctl_snprintf(uctl, "ERR in tot %d percentage\n", tot); + goto error_return; + } + + spec->percent_count = (j>>1); + + break; + default: + istgt_uctl_snprintf(uctl, "ERR invalid option %d\n", setopt); + goto error_return; + } + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; +} + +static int +istgt_uctl_cmd_persist(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + char *persistopt; + int lun_i; + int rc; + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + persistopt = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun == NULL) { + lun_i = 0; + } + else { + lun_i = (int) strtol(lun, NULL, 10); + } + + if(persistopt == NULL) { + istgt_uctl_snprintf(uctl, "ERR no persistopt\n"); + goto error_return; + } + + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + if (lu->type == ISTGT_LU_TYPE_DISK) { + MTX_LOCK(&lu->mutex); + rc = istgt_lu_disk_persist_reservation(lu, lun_i, persistopt); + MTX_UNLOCK(&lu->mutex); + if(rc < 0) + istgt_uctl_snprintf(uctl, "ERR in persist cmd execution\n"); + } + else { + istgt_uctl_snprintf(uctl, "ERR clear_rsv \n"); + rc = -1; + } + + if (rc < 0) { + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + /* logging event */ + ISTGT_NOTICELOG("Unit Rsv_Persist %s lun%d from %s\n", iqn, lun_i, uctl->caddr); + /* Persist succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + + +static int +istgt_uctl_cmd_list(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + char *mflags; + char *mfile; + char *msize; + char *mtype; + char *workp; + int lun_i; + int worksize; + int present; + int lock; + int rc; + int i; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (iqn == NULL) { + /* all targets */ + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + istgt_uctl_snprintf(uctl, "%s %s LU%d\n", uctl->cmd, lu->name, lu->num); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + } + MTX_UNLOCK(&uctl->istgt->mutex); + } else { + /* specified target */ + MTX_LOCK(&uctl->istgt->mutex); + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + MTX_UNLOCK(&uctl->istgt->mutex); + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + MTX_UNLOCK(&uctl->istgt->mutex); + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + + worksize = uctl->worksize; + workp = uctl->work; + + switch (llp->type) { + case ISTGT_LU_LUN_TYPE_REMOVABLE: + mflags = istgt_lu_get_media_flags_string(llp->u.removable.flags, + workp, worksize); + worksize -= strlen(mflags) + 1; + workp += strlen(mflags) + 1; + present = istgt_uctl_get_media_present(lu, lun_i); + lock = istgt_uctl_get_media_lock(lu, lun_i); + mfile = llp->u.removable.file; + if (llp->u.removable.flags & ISTGT_LU_FLAG_MEDIA_AUTOSIZE) { + snprintf(workp, worksize, "auto"); + } else { + snprintf(workp, worksize, "%"PRIu64, + llp->u.removable.size); + } + msize = workp; + worksize -= strlen(msize) + 1; + workp += strlen(msize) + 1; + snprintf(workp, worksize, "-"); + mtype = workp; + worksize -= strlen(msize) + 1; + workp += strlen(msize) + 1; + + istgt_uctl_snprintf(uctl, "%s lun%u %s %s %s %s %s \"%s\" %s\n", + uctl->cmd, lun_i, + "removable", + (present ? "present" : "absent"), + (lock ? "lock" : "unlock"), + mtype, mflags, mfile, msize); + rc = istgt_uctl_writeline(uctl); + break; + case ISTGT_LU_LUN_TYPE_STORAGE: + mfile = llp->u.storage.file; + snprintf(workp, worksize, "%"PRIu64, + llp->u.storage.size); + msize = workp; + worksize -= strlen(msize) + 1; + workp += strlen(msize) + 1; + + istgt_uctl_snprintf(uctl, "%s lun%u %s \"%s\" %s\n", + uctl->cmd, lun_i, + "storage", + mfile, msize); + rc = istgt_uctl_writeline(uctl); + break; + case ISTGT_LU_LUN_TYPE_DEVICE: + mfile = llp->u.device.file; + + istgt_uctl_snprintf(uctl, "%s lun%u %s \"%s\"\n", + uctl->cmd, lun_i, + "device", + mfile); + rc = istgt_uctl_writeline(uctl); + break; + case ISTGT_LU_LUN_TYPE_SLOT: + default: + MTX_UNLOCK(&uctl->istgt->mutex); + istgt_uctl_snprintf(uctl, "ERR unsupport LUN type\n"); + goto error_return; + } + + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + MTX_UNLOCK(&uctl->istgt->mutex); + } + + /* list succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_unload(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) { + istgt_uctl_snprintf(uctl, "ERR not removable\n"); + goto error_return; + } + + rc = 0; + /* unload media from lun + switch (lu->type) { + case ISTGT_LU_TYPE_DVD: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_dvd_unload_media(lu->lun[lun_i].spec); + MTX_UNLOCK(&lu->mutex); + break; + case ISTGT_LU_TYPE_TAPE: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_tape_unload_media(lu->lun[lun_i].spec); + MTX_UNLOCK(&lu->mutex); + break; + default: + rc = -1; + }*/ + + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR unload\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Media Unload %s lun%d from %s\n", + iqn, lun_i, uctl->caddr); + + /* unload succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_load(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) { + istgt_uctl_snprintf(uctl, "ERR not removable\n"); + goto error_return; + } + + rc = -1; + /* load media to lun + switch (lu->type) { + case ISTGT_LU_TYPE_DVD: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_dvd_load_media(lu->lun[lun_i].spec); + MTX_UNLOCK(&lu->mutex); + break; + case ISTGT_LU_TYPE_TAPE: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_tape_load_media(lu->lun[lun_i].spec); + MTX_UNLOCK(&lu->mutex); + break; + default: + rc = -1; + }*/ + + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR load\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Media Load %s lun%d from %s\n", + iqn, lun_i, uctl->caddr); + + /* load succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_change(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char empty_flags[] = "ro"; + char empty_size[] = "0"; + char *arg; + char *iqn; + char *lun; + char *type; + char *flags; + char *file; + char *size; + char *safedir; + char *fullpath; + char *abspath; + int lun_i; + int len; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + type = strsepq(&arg, delim); + flags = strsepq(&arg, delim); + file = strsepq(&arg, delim); + size = strsepq(&arg, delim); + + if (iqn == NULL || lun == NULL || type == NULL || flags == NULL + || file == NULL || size == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) { + istgt_uctl_snprintf(uctl, "ERR not removable\n"); + goto error_return; + } + + /* make safe directory (start '/', end '/') */ + len = 1 + strlen(uctl->mediadirectory) + 1 + 1; + safedir = xmalloc(len); + if (uctl->mediadirectory[0] != '/') { + ISTGT_WARNLOG("MediaDirectory is not starting with '/'\n"); + snprintf(safedir, len, "/%s", uctl->mediadirectory); + } else { + snprintf(safedir, len, "%s", uctl->mediadirectory); + } + if (strlen(safedir) > 1 && safedir[strlen(safedir) - 1] != '/') { + safedir[strlen(safedir) + 1] = '\0'; + safedir[strlen(safedir)] = '/'; + } + + /* check abspath in mediadirectory? */ + len = strlen(safedir) + strlen(file) + 1; + fullpath = xmalloc(len); + if (file[0] != '/') { + snprintf(fullpath, len, "%s%s", safedir, file); + } else { + snprintf(fullpath, len, "%s", file); + } +#ifdef PATH_MAX + abspath = xmalloc(len + PATH_MAX); + file = realpath(fullpath, abspath); +#else +/* + { + long path_max; + path_max = pathconf(fullpath, _PC_PATH_MAX); + if (path_max != -1L) { + abspath = xmalloc(path_max); + file = realpath(fullpath, abspath); + } + } +*/ + file = abspath = realpath(fullpath, NULL); +#endif /* PATH_MAX */ + if (file == NULL) { + ISTGT_ERRLOG("realpath(%s) failed\n", fullpath); + internal_error: + xfree(safedir); + xfree(fullpath); + xfree(abspath); + istgt_uctl_snprintf(uctl, "ERR %s internal error\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (strcasecmp(file, "/dev/null") == 0) { + /* OK, empty slot */ + flags = empty_flags; + size = empty_size; + } else if (strncasecmp(file, safedir, strlen(safedir)) != 0) { + ISTGT_ERRLOG("Realpath(%s) is not within MediaDirectory(%s)\n", + file, safedir); + goto internal_error; + } + + rc = -1; + /* unload and load media from lun + switch (lu->type) { + case ISTGT_LU_TYPE_DVD: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_dvd_change_media(lu->lun[lun_i].spec, + type, flags, file, size); + MTX_UNLOCK(&lu->mutex); + break; + case ISTGT_LU_TYPE_TAPE: + MTX_LOCK(&lu->mutex); + rc = istgt_lu_tape_change_media(lu->lun[lun_i].spec, + type, flags, file, size); + MTX_UNLOCK(&lu->mutex); + break; + default: + rc = -1; + }*/ + + if (rc < 0) { + xfree(safedir); + xfree(fullpath); + xfree(abspath); + istgt_uctl_snprintf(uctl, "ERR change\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Media Change \"%s %s %s %s\" on %s lun%d from %s\n", + type, flags, file, size, iqn, lun_i, uctl->caddr); + + xfree(safedir); + xfree(fullpath); + xfree(abspath); + + /* change succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_reset(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc = 0, cleared = 0; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + + /* reset lun */ + switch (lu->type) { + case ISTGT_LU_TYPE_DISK: + MTX_LOCK(&lu->mutex); + cleared = istgt_lu_disk_reset(lu, lun_i, 0); + MTX_UNLOCK(&lu->mutex); + break; + case ISTGT_LU_TYPE_DVD: + case ISTGT_LU_TYPE_TAPE: + case ISTGT_LU_TYPE_NONE: + case ISTGT_LU_TYPE_PASS: + cleared = -1; + break; + default: + cleared = -1; + } + + if (cleared < 0) { + istgt_uctl_snprintf(uctl, "ERR reset\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Unit Reset %s lun%d from %s\n", + iqn, lun_i, uctl->caddr); + + /* reset succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_clear(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + + if (lu->type == ISTGT_LU_TYPE_DISK) { + MTX_LOCK(&lu->mutex); + rc = istgt_lu_disk_clear_reservation(lu, lun_i); + MTX_UNLOCK(&lu->mutex); + if(rc < 0) + istgt_uctl_snprintf(uctl, "ERR in clear cmd execution\n"); + } + else { + istgt_uctl_snprintf(uctl, "ERR clear_rsv \n"); + rc = -1; + } + + if (rc < 0) { + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + /* logging event */ + ISTGT_NOTICELOG("Unit Rsv_Clear %s lun%d\n", + iqn, lun_i); + + /* Clear succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + + +static int +istgt_uctl_cmd_refresh(UCTL_Ptr uctl) +{ + int rc; + int inconfig = 0; + + MTX_LOCK(&uctl->istgt->state_mutex); + if (uctl->istgt->inconfig == 1) + inconfig = 1; + else + uctl->istgt->inconfig = 1; + MTX_UNLOCK(&uctl->istgt->state_mutex); + if (inconfig == 1) { + ISTGT_LOG("Previous istgtcontrol refresh/load is still running..n"); + istgt_uctl_snprintf(uctl, "Error Previous Refresh command still running\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + rc = istgt_reload(uctl->istgt); + + MTX_LOCK(&uctl->istgt->state_mutex); + uctl->istgt->inconfig = 0; + MTX_UNLOCK(&uctl->istgt->state_mutex); + + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR Refresh\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* Refresh succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_start(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + + /* start lun */ + rc = istgt_lu_disk_start(lu, lun_i); + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR start\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Unit Start %s lun%d from %s\n", + iqn, lun_i, uctl->caddr); + + /* stop succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_stop(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_LUN_Ptr llp; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (iqn == NULL || arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + lu = istgt_lu_find_target(uctl->istgt, iqn); + if (lu == NULL) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + error_return: + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lun_i < 0 || lun_i >= lu->maxlun) { + istgt_uctl_snprintf(uctl, "ERR no target\n"); + goto error_return; + } + llp = &lu->lun[lun_i]; + if (llp->type == ISTGT_LU_LUN_TYPE_NONE) { + istgt_uctl_snprintf(uctl, "ERR no LUN\n"); + goto error_return; + } + + /* stop lun */ + rc = istgt_lu_disk_stop(lu, lun_i); + if (rc < 0) { + istgt_uctl_snprintf(uctl, "ERR stop\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + /* logging event */ + ISTGT_NOTICELOG("Unit Stop %s lun%d from %s\n", + iqn, lun_i, uctl->caddr); + + /* stop succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_modify(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *OperationalMode; + int dofake; + int rc; + int inmodify = 0; + arg = uctl->arg; + OperationalMode = strsepq(&arg, delim); + + if (OperationalMode == NULL) { + dofake = 0; + } else { + dofake = (int) strtol(OperationalMode, NULL, 10); + } + + if (dofake < 0 || arg != NULL) { + ISTGT_LOG("modify %d returning.. ERR invalid parameters\n", dofake); + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + MTX_LOCK(&uctl->istgt->state_mutex); + if (uctl->istgt->inmodify == 1) + inmodify = 1; + else + uctl->istgt->inmodify = 1; + MTX_UNLOCK(&uctl->istgt->state_mutex); + if (inmodify == 1) { + ISTGT_LOG("istgtcontrol modify is still running.."); + return UCTL_CMD_ERR; + } + + /* Modify all the lun */ + rc = istgt_lu_disk_modify(uctl->istgt, dofake); + + MTX_LOCK(&uctl->istgt->state_mutex); + uctl->istgt->inmodify = 0; + MTX_UNLOCK(&uctl->istgt->state_mutex); + + if (rc < 0) { + ISTGT_LOG("modify %d returning.. ERR stop\n", dofake); + istgt_uctl_snprintf(uctl, "ERR stop\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + uctl->istgt->OperationalMode = dofake; + + /* Modify succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_mem(UCTL_Ptr uctl) +{ + int rc; + char memBuf[4096]; + int mlen = 4090; + + rc = poolprint(memBuf, mlen); + + /* succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +extern int memdebug; +static int +istgt_uctl_cmd_memdebug(UCTL_Ptr uctl) +{ + int rc; + + if (memdebug == 1) { + memdebug = 0; + istgt_uctl_snprintf(uctl, "OK debug-OFF %s\n", uctl->cmd); + } else { + memdebug = 1; + istgt_uctl_snprintf(uctl, "OK debug-ON %s\n", uctl->cmd); + } + + /* succeeded */ + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} +extern int g_logtimes; +extern uint64_t g_logdelayns; + +static int +istgt_uctl_cmd_log(UCTL_Ptr uctl) +{ + int rc; + int changetrace = 0; + int newtrace = 0; + int newdelay = 0; + int oldtrace = g_trace_flag; + int oldlogtimes = g_logtimes; + uint64_t olddelayms = g_logdelayns; + + const char *delim = ARGS_DELIM; + char *arg; + char *gottracestr; + char *tracestr; + char *delaystr; + + arg = uctl->arg; + gottracestr = strsepq(&arg, delim); + tracestr = strsepq(&arg, delim); + delaystr= strsepq(&arg, delim); + + if (gottracestr == NULL) + changetrace = 0; + else + changetrace = (int) strtol(gottracestr, NULL, 10); + + if (tracestr == NULL) + newtrace = 0; + else + newtrace = (int) strtol(tracestr, NULL, 10); + + if (delaystr == NULL) + newdelay = 0; + else + newdelay = (int) strtol(delaystr, NULL, 10); + + if (changetrace == 1) + g_trace_flag = newtrace; + + if (newdelay == -2) { + //leave it untouched + } else if (newdelay == -1) { + g_logtimes = 0; + } else { + g_logtimes = 1; + g_logdelayns = newdelay * 1000; + } + if (g_logdelayns < 1) + g_logdelayns = 0; + + ISTGT_LOG("cmd_log[%s] trace:%x->%x delayedlog:%d->%d us:%ld->%ld\n", + uctl->cmd, oldtrace, g_trace_flag, oldlogtimes, g_logtimes, + olddelayms > 0 ? olddelayms/1000: 0, + g_logdelayns > 0 ? g_logdelayns/1000: 0); + + istgt_uctl_snprintf(uctl, "OK cmd_log[%s] trace:%x->%x delayedlog:%d->%d ms:%ld->%ld\n", + uctl->cmd, oldtrace, g_trace_flag, oldlogtimes, g_logtimes, + olddelayms > 0 ? olddelayms/1000000: 0, + g_logdelayns > 0 ? g_logdelayns/1000000: 0); + + /* succeeded */ + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_info(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + CONN_Ptr conn; + SESS_Ptr sess; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + int ncount; + int rc; + int i, j, k; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + ncount = 0; + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (iqn != NULL && strcasecmp(iqn, lu->name) != 0) + continue; + + istgt_lock_gconns(); + MTX_LOCK(&lu->mutex); + for (j = 1; j < MAX_LU_TSIH; j++) { + if (lu->tsih[j].initiator_port != NULL + && lu->tsih[j].tsih != 0) { + conn = istgt_find_conn(lu->tsih[j].initiator_port, + lu->name, lu->tsih[j].tsih); + if (conn == NULL || conn->sess == NULL) + continue; + + sess = conn->sess; + MTX_LOCK(&sess->mutex); + for (k = 0; k < sess->connections; k++) { + conn = sess->conns[k]; + if (conn == NULL) + continue; + + istgt_uctl_snprintf(uctl, "%s w#%d: Login from %s (%s) on %s LU%d LU_Online=%s" + " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u," + " CID=%u, HeaderDigest=%s, DataDigest=%s," + " MaxConnections=%u," + " FirstBurstLength=%u, MaxBurstLength=%u," + " MaxRecvDataSegmentLength=%u," + " InitialR2T=%s, ImmediateData=%s, PendingPDUs=%d\n", + uctl->cmd, + conn->id, + conn->initiator_name, + conn->initiator_addr, + conn->target_name, lu->num, + (lu->online ? "Yes" : "No"), + conn->portal.host, conn->portal.port, + conn->portal.tag, + conn->sess->isid, conn->sess->tsih, + conn->cid, + (conn->header_digest ? "on" : "off"), + (conn->data_digest ? "on" : "off"), + conn->sess->MaxConnections, + conn->sess->FirstBurstLength, + conn->sess->MaxBurstLength, + conn->MaxRecvDataSegmentLength, + (conn->sess->initial_r2t ? "Yes" : "No"), + (conn->sess->immediate_data ? "Yes" : "No"), + conn->pending_pdus.num); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&sess->mutex); + MTX_UNLOCK(&lu->mutex); + istgt_unlock_gconns(); + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + ncount++; + } + MTX_UNLOCK(&sess->mutex); + } + } + MTX_UNLOCK(&lu->mutex); + istgt_unlock_gconns(); + } + MTX_UNLOCK(&uctl->istgt->mutex); + if (ncount == 0) { + istgt_uctl_snprintf(uctl, "%s no login\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + + /* info succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} +static int +istgt_uctl_cmd_status(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + char *lun; + int lun_i; + int status; + int i; + int rc; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + lun = strsepq(&arg, delim); + + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + if (lun == NULL) { + lun_i = 0; + } else { + lun_i = (int) strtol(lun, NULL, 10); + } + + /* Print Operational Mode */ + istgt_uctl_snprintf(uctl, "%s Running:%s\n", uctl->cmd, + (uctl->istgt->OperationalMode)? "FAKE MODE OF OPERATION" : "NORMAL MODE OF OPERATION"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (iqn != NULL && strcasecmp(iqn, lu->name) != 0) + continue; + /* Fetch status */ + status = istgt_lu_disk_status(lu, lun_i); + if (status < 0) { + istgt_uctl_snprintf(uctl, "ERR status\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + MTX_UNLOCK(&uctl->istgt->mutex); + return UCTL_CMD_ERR; + } + /* Print Status */ + istgt_uctl_snprintf(uctl, "%s %s %s\n", uctl->cmd, lu->name, (status == ISTGT_LUN_BUSY) ? "FAKE" : "REAL"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + } + MTX_UNLOCK(&uctl->istgt->mutex); + + /* status succeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_maxtime(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_DISK *spec; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + int rc; + int i; + char *zero = NULL; + int setzero = 0; + int ind = 0; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + if (arg) + zero = strsepq(&arg, delim); + if (zero != NULL) { + i = (int) strtol(zero, NULL, 10); + if (i == 1) + setzero = 1; + } + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + for (i = 1; i <= uctl->istgt->nlogical_unit; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if ((iqn != NULL && strcmp(iqn, lu->name) != 0) && (strcmp(iqn, "ALL") != 0)) + continue; + + spec = (ISTGT_LU_DISK *)lu->lun[0].spec; + if(setzero == 1) { + for(ind=0; ind<10;ind++) { + spec->IO_size[ind].write.total_time.tv_sec = 0; + spec->IO_size[ind].write.total_time.tv_nsec = 0; + spec->IO_size[ind].read.total_time.tv_sec = 0; + spec->IO_size[ind].read.total_time.tv_nsec = 0; + spec->IO_size[ind].cmp_n_write.total_time.tv_sec = 0; + spec->IO_size[ind].cmp_n_write.total_time.tv_nsec = 0; + spec->IO_size[ind].unmp.total_time.tv_sec = 0; + spec->IO_size[ind].unmp.total_time.tv_nsec = 0; + spec->IO_size[ind].write_same.total_time.tv_sec = 0; + spec->IO_size[ind].write_same.total_time.tv_nsec = 0; + } + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; + } + istgt_uctl_snprintf(uctl, "%s LU%d %s\n", uctl->cmd, lu->num, lu->name); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + for(ind=0; ind<10;ind++) { + if(spec->IO_size[ind].write.total_time.tv_sec != 0 || spec->IO_size[ind].write.total_time.tv_nsec != 0) { + istgt_uctl_snprintf(uctl, "%s WR |%10lu + %4lu| %ld.%9.9ld [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]\n", uctl->cmd, spec->IO_size[ind].write.lba, spec->IO_size[ind].write.lblen, + spec->IO_size[ind].write.total_time.tv_sec, spec->IO_size[ind].write.total_time.tv_nsec, + spec->IO_size[ind].write.caller[1] ? spec->IO_size[ind].write.caller[1] : '9', + spec->IO_size[ind].write.tdiff[1].tv_sec, spec->IO_size[ind].write.tdiff[1].tv_nsec, + spec->IO_size[ind].write.caller[2] ? spec->IO_size[ind].write.caller[2] : '9', + spec->IO_size[ind].write.tdiff[2].tv_sec, spec->IO_size[ind].write.tdiff[2].tv_nsec, + spec->IO_size[ind].write.caller[3] ? spec->IO_size[ind].write.caller[3] : '9', + spec->IO_size[ind].write.tdiff[3].tv_sec, spec->IO_size[ind].write.tdiff[3].tv_nsec, + spec->IO_size[ind].write.caller[4] ? spec->IO_size[ind].write.caller[4] : '9', + spec->IO_size[ind].write.tdiff[4].tv_sec, spec->IO_size[ind].write.tdiff[4].tv_nsec, + spec->IO_size[ind].write.caller[5] ? spec->IO_size[ind].write.caller[5] : '9', + spec->IO_size[ind].write.tdiff[5].tv_sec, spec->IO_size[ind].write.tdiff[5].tv_nsec, + spec->IO_size[ind].write.caller[6] ? spec->IO_size[ind].write.caller[6] : '9', + spec->IO_size[ind].write.tdiff[6].tv_sec, spec->IO_size[ind].write.tdiff[6].tv_nsec, + spec->IO_size[ind].write.caller[7] ? spec->IO_size[ind].write.caller[7] : '9', + spec->IO_size[ind].write.tdiff[7].tv_sec, spec->IO_size[ind].write.tdiff[7].tv_nsec, + spec->IO_size[ind].write.caller[8] ? spec->IO_size[ind].write.caller[8] : '9', + spec->IO_size[ind].write.tdiff[8].tv_sec, spec->IO_size[ind].write.tdiff[8].tv_nsec + ); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + } + for(ind=0; ind<10;ind++) { + if(spec->IO_size[ind].read.total_time.tv_sec != 0 || spec->IO_size[ind].read.total_time.tv_nsec != 0){ + istgt_uctl_snprintf(uctl, "%s RD |%10lu + %4lu| %ld.%9.9ld [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]\n", uctl->cmd, spec->IO_size[ind].read.lba, spec->IO_size[ind].read.lblen, + spec->IO_size[ind].read.total_time.tv_sec, spec->IO_size[ind].read.total_time.tv_nsec, + spec->IO_size[ind].read.caller[1] ? spec->IO_size[ind].read.caller[1] : '9', + spec->IO_size[ind].read.tdiff[1].tv_sec, spec->IO_size[ind].read.tdiff[1].tv_nsec, + spec->IO_size[ind].read.caller[2] ? spec->IO_size[ind].read.caller[2] : '9', + spec->IO_size[ind].read.tdiff[2].tv_sec, spec->IO_size[ind].read.tdiff[2].tv_nsec, + spec->IO_size[ind].read.caller[3] ? spec->IO_size[ind].read.caller[3] : '9', + spec->IO_size[ind].read.tdiff[3].tv_sec, spec->IO_size[ind].read.tdiff[3].tv_nsec, + spec->IO_size[ind].read.caller[4] ? spec->IO_size[ind].read.caller[4] : '9', + spec->IO_size[ind].read.tdiff[4].tv_sec, spec->IO_size[ind].read.tdiff[4].tv_nsec, + spec->IO_size[ind].read.caller[5] ? spec->IO_size[ind].read.caller[5] : '9', + spec->IO_size[ind].read.tdiff[5].tv_sec, spec->IO_size[ind].read.tdiff[5].tv_nsec, + spec->IO_size[ind].read.caller[6] ? spec->IO_size[ind].read.caller[6] : '9', + spec->IO_size[ind].read.tdiff[6].tv_sec, spec->IO_size[ind].read.tdiff[6].tv_nsec, + spec->IO_size[ind].read.caller[7] ? spec->IO_size[ind].read.caller[7] : '9', + spec->IO_size[ind].read.tdiff[7].tv_sec, spec->IO_size[ind].read.tdiff[7].tv_nsec, + spec->IO_size[ind].read.caller[8] ? spec->IO_size[ind].read.caller[8] : '9', + spec->IO_size[ind].read.tdiff[8].tv_sec, spec->IO_size[ind].read.tdiff[8].tv_nsec + ); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + } + for(ind=0; ind<10;ind++) { + if(spec->IO_size[ind].cmp_n_write.total_time.tv_sec != 0 || spec->IO_size[ind].cmp_n_write.total_time.tv_nsec != 0){ + istgt_uctl_snprintf(uctl, "%s CMP_n_WR |%10lu + %4lu| %ld.%9.9ld [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]\n", uctl->cmd, spec->IO_size[ind].cmp_n_write.lba, spec->IO_size[ind].cmp_n_write.lblen, + spec->IO_size[ind].cmp_n_write.total_time.tv_sec, spec->IO_size[ind].cmp_n_write.total_time.tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[1] ? spec->IO_size[ind].cmp_n_write.caller[1] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[1].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[1].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[2] ? spec->IO_size[ind].cmp_n_write.caller[2] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[2].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[2].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[3] ? spec->IO_size[ind].cmp_n_write.caller[3] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[3].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[3].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[4] ? spec->IO_size[ind].cmp_n_write.caller[4] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[4].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[4].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[5] ? spec->IO_size[ind].cmp_n_write.caller[5] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[5].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[5].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[6] ? spec->IO_size[ind].cmp_n_write.caller[6] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[6].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[6].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[7] ? spec->IO_size[ind].cmp_n_write.caller[7] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[7].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[7].tv_nsec, + spec->IO_size[ind].cmp_n_write.caller[8] ? spec->IO_size[ind].cmp_n_write.caller[8] : '9', + spec->IO_size[ind].cmp_n_write.tdiff[8].tv_sec, spec->IO_size[ind].cmp_n_write.tdiff[8].tv_nsec + ); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + } + for(ind=0; ind<10;ind++) { + if(spec->IO_size[ind].unmp.total_time.tv_sec != 0 || spec->IO_size[ind].unmp.total_time.tv_nsec != 0){ + istgt_uctl_snprintf(uctl, "%s UNMP |%10lu + %4lu| %ld.%9.9ld [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]\n", uctl->cmd, spec->IO_size[ind].unmp.lba, spec->IO_size[ind].unmp.lblen, + spec->IO_size[ind].unmp.total_time.tv_sec, spec->IO_size[ind].unmp.total_time.tv_nsec, + spec->IO_size[ind].unmp.caller[1] ? spec->IO_size[ind].unmp.caller[1] : '9', + spec->IO_size[ind].unmp.tdiff[1].tv_sec, spec->IO_size[ind].unmp.tdiff[1].tv_nsec, + spec->IO_size[ind].unmp.caller[2] ? spec->IO_size[ind].unmp.caller[2] : '9', + spec->IO_size[ind].unmp.tdiff[2].tv_sec, spec->IO_size[ind].unmp.tdiff[2].tv_nsec, + spec->IO_size[ind].unmp.caller[3] ? spec->IO_size[ind].unmp.caller[3] : '9', + spec->IO_size[ind].unmp.tdiff[3].tv_sec, spec->IO_size[ind].unmp.tdiff[3].tv_nsec, + spec->IO_size[ind].unmp.caller[4] ? spec->IO_size[ind].unmp.caller[4] : '9', + spec->IO_size[ind].unmp.tdiff[4].tv_sec, spec->IO_size[ind].unmp.tdiff[4].tv_nsec, + spec->IO_size[ind].unmp.caller[5] ? spec->IO_size[ind].unmp.caller[5] : '9', + spec->IO_size[ind].unmp.tdiff[5].tv_sec, spec->IO_size[ind].unmp.tdiff[5].tv_nsec, + spec->IO_size[ind].unmp.caller[6] ? spec->IO_size[ind].unmp.caller[6] : '9', + spec->IO_size[ind].unmp.tdiff[6].tv_sec, spec->IO_size[ind].unmp.tdiff[6].tv_nsec, + spec->IO_size[ind].unmp.caller[7] ? spec->IO_size[ind].unmp.caller[7] : '9', + spec->IO_size[ind].unmp.tdiff[7].tv_sec, spec->IO_size[ind].unmp.tdiff[7].tv_nsec, + spec->IO_size[ind].unmp.caller[8] ? spec->IO_size[ind].unmp.caller[8] : '9', + spec->IO_size[ind].unmp.tdiff[8].tv_sec, spec->IO_size[ind].unmp.tdiff[8].tv_nsec + ); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + } + for(ind=0; ind<10;ind++) { + if(spec->IO_size[ind].write_same.total_time.tv_sec != 0 || spec->IO_size[ind].write_same.total_time.tv_nsec != 0){ + istgt_uctl_snprintf(uctl, "%s WR_SAME |%10lu + %4lu| %ld.%9.9ld [%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld]\n", uctl->cmd, spec->IO_size[ind].write_same.lba, spec->IO_size[ind].write_same.lblen, + spec->IO_size[ind].write_same.total_time.tv_sec, spec->IO_size[ind].write_same.total_time.tv_nsec, + spec->IO_size[ind].write_same.caller[1] ? spec->IO_size[ind].write_same.caller[1] : '9', + spec->IO_size[ind].write_same.tdiff[1].tv_sec, spec->IO_size[ind].write_same.tdiff[1].tv_nsec, + spec->IO_size[ind].write_same.caller[2] ? spec->IO_size[ind].write_same.caller[2] : '9', + spec->IO_size[ind].write_same.tdiff[2].tv_sec, spec->IO_size[ind].write_same.tdiff[2].tv_nsec, + spec->IO_size[ind].write_same.caller[3] ? spec->IO_size[ind].write_same.caller[3] : '9', + spec->IO_size[ind].write_same.tdiff[3].tv_sec, spec->IO_size[ind].write_same.tdiff[3].tv_nsec, + spec->IO_size[ind].write_same.caller[4] ? spec->IO_size[ind].write_same.caller[4] : '9', + spec->IO_size[ind].write_same.tdiff[4].tv_sec, spec->IO_size[ind].write_same.tdiff[4].tv_nsec, + spec->IO_size[ind].write_same.caller[5] ? spec->IO_size[ind].write_same.caller[5] : '9', + spec->IO_size[ind].write_same.tdiff[5].tv_sec, spec->IO_size[ind].write_same.tdiff[5].tv_nsec, + spec->IO_size[ind].write_same.caller[6] ? spec->IO_size[ind].write_same.caller[6] : '9', + spec->IO_size[ind].write_same.tdiff[6].tv_sec, spec->IO_size[ind].write_same.tdiff[6].tv_nsec, + spec->IO_size[ind].write_same.caller[7] ? spec->IO_size[ind].write_same.caller[7] : '9', + spec->IO_size[ind].write_same.tdiff[7].tv_sec, spec->IO_size[ind].write_same.tdiff[7].tv_nsec, + spec->IO_size[ind].write_same.caller[8] ? spec->IO_size[ind].write_same.caller[8] : '9', + spec->IO_size[ind].write_same.tdiff[8].tv_sec, spec->IO_size[ind].write_same.tdiff[8].tv_nsec + ); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + } + } + + /* info succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} +static int +istgt_uctl_cmd_dump(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_DISK *spec; + CONN_Ptr conn; + SESS_Ptr sess; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + int ncount = 0; + int lu_num = 0; + int rc; + int i, j, k, t; + int x = 0; + int detail = 0; + PORTAL_GROUP *pgp; + char temp[2048]; + char size[100]; + char *c_size = size; + char *bp = temp; + int count = 0; + int rem = 2048 , ln = 0; + uint64_t temp_s = 0, temp_s2 = 0; + + arg = uctl->arg; + detail = atoi(strsepq(&arg, delim)); + iqn = strsepq(&arg, delim); + + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (iqn != NULL && strcasecmp(iqn, lu->name) != 0) + continue; + lu_num++; + count = 0; + + istgt_lock_gconns(); + MTX_LOCK(&lu->mutex); + for (j = 0; j < lu->maxmap; j++) { + pgp = istgt_lu_find_portalgroup(uctl->istgt, lu->map[j].pg_tag); + if(pgp != NULL) { + for( x = 0; x < pgp->nportals; x++) { + ln = snprintf(bp, 256, " IP%d:%s ", x+1, pgp->portals[x]->host); + if(ln <0) + ln = 0; + else if(ln > rem) + ln = rem; + rem -= ln; + bp += ln; + *bp = '\0'; + } + } + } + bp = temp; + spec = (ISTGT_LU_DISK *)lu->lun[0].spec; + temp_s = spec->size; + do { + if(temp_s/1024 == 0) + break; + else { + count++; + temp_s2 = temp_s % 1024; + temp_s /= 1024; + } + }while(1); + switch(count) { + case 0: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'B'); break; + case 1: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'K'); break; + case 2: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'M'); break; + case 3: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'G'); break; + case 4: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'T'); break; + case 5: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'P'); break; + case 6: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'E'); break; + case 7: snprintf(c_size, 100, "%lu.%lu%c", temp_s, temp_s2, 'Z'); break; + } + if(detail == 1) + istgt_uctl_snprintf(uctl, "%s LUN LU%d %s Luworkers:%d Qdepth:%d Size:%s Blocklength:%lu PhysRecordLength:%d Unmap:%s Wzero:%s ATS:%s XCOPY:%s %s CONNECTIONS:%d\n", + uctl->cmd, lu->num, lu->name, lu->luworkers, lu->queue_depth, c_size, + spec->blocklen, lu->recordsize, + (spec->unmap == 1) ? "Enabled":"Disabled", + (spec->wzero == 1) ? "Enabled":"Disabled", + (spec->ats == 1) ? "Enabled":"Disabled", + (spec->xcopy == 1) ? "Enabled":"Disabled", + temp, lu->conns); + else + istgt_uctl_snprintf(uctl, "%s LUN LU%d %s %s CONNECTIONS:%d\n",uctl->cmd, lu->num, lu->name, temp, lu->conns); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&lu->mutex); + istgt_unlock_gconns(); + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + + for (j = 1; j < MAX_LU_TSIH; j++) { + if (lu->tsih[j].initiator_port != NULL + && lu->tsih[j].tsih != 0) { + conn = istgt_find_conn(lu->tsih[j].initiator_port, + lu->name, lu->tsih[j].tsih); + if (conn == NULL || conn->sess == NULL) + continue; + + sess = conn->sess; + MTX_LOCK(&sess->mutex); + for (k = 0; k < sess->connections; k++) { + conn = sess->conns[k]; + if (conn == NULL) + continue; + + for (t = 0; t < lu->maxmap; t++) { + pgp = istgt_lu_find_portalgroup(uctl->istgt, lu->map[t].pg_tag); + if(pgp != NULL) { + for( x = 0; x < pgp->nportals; x++) { + if(!strcmp(pgp->portals[x]->host, conn->target_addr)) { + break; + } + } + } + } + istgt_uctl_snprintf(uctl, "%s CONN c#%d" + " %"PRIx64" %u %u IP%d %s %s\n", + uctl->cmd, + conn->id, + conn->sess->isid, conn->sess->tsih, + conn->cid, x+1, + conn->initiator_addr, conn->initiator_name); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + MTX_UNLOCK(&sess->mutex); + MTX_UNLOCK(&lu->mutex); + istgt_unlock_gconns(); + MTX_UNLOCK(&uctl->istgt->mutex); + return rc; + } + ncount++; + } + MTX_UNLOCK(&sess->mutex); + } + } + MTX_UNLOCK(&lu->mutex); + istgt_unlock_gconns(); + } + MTX_UNLOCK(&uctl->istgt->mutex); + + istgt_uctl_snprintf(uctl, "%s TOTAL LOGICAL_UNITS:%d CONNECTIONS:%d\n", uctl->cmd, lu_num, ncount); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + if (ncount == 0) { + istgt_uctl_snprintf(uctl, "%s no login\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + + /* info succeeded */ + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +static int +istgt_uctl_cmd_rsv(UCTL_Ptr uctl) +{ + ISTGT_LU_Ptr lu; + const char *delim = ARGS_DELIM; + char *arg; + char *iqn; + int rc; + int i; + + arg = uctl->arg; + iqn = strsepq(&arg, delim); + + if (arg != NULL) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (iqn != NULL && strcasecmp(iqn, lu->name) != 0) + continue; + (void)istgt_lu_disk_print_reservation(lu, 0); //CB has only lun 0 + } + MTX_UNLOCK(&uctl->istgt->mutex); + + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +extern clockid_t clockid; + +static int +istgt_uctl_cmd_que(UCTL_Ptr uctl) +{ +#define adjbuf() { \ + if (wn < 0) \ + wn = 0; \ + else if (wn > brem) \ + wn = brem; \ + bptr += wn; \ + brem -= wn; \ +} +#define tdiff(_s, _n, _r) { \ + if ((_n.tv_nsec - _s.tv_nsec) < 0) { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec-1; \ + _r.tv_nsec = 1000000000 + _n.tv_nsec - _s.tv_nsec; \ + } else { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec; \ + _r.tv_nsec = _n.tv_nsec - _s.tv_nsec; \ + } \ +} +#define _BSZ_ 4086 + char buf[_BSZ_+10]; + int brem = _BSZ_, wn = 0; + int toprint, chunk, j; + char *bptr = buf; + + ISTGT_LU_Ptr lu; + const char *delim = ARGS_DELIM; + char *arg, *subcmd; + char *iqn = NULL, *lu_str = NULL; + int rc, err=0; + int i, levels; + int lu_num = -1; + int cq, bq, inf, inflight; + ISTGT_LU_DISK *spec; +#if 0 + ISTGT_LU_TASK_Ptr tptr; + void *cookie=NULL; + struct timespec r; +#endif + struct timespec now, now1; + int unlocked = 0; + + arg = uctl->arg; + subcmd = strsepq(&arg, delim); + if (subcmd != NULL) { + if (strcasecmp(subcmd, "IQN") == 0) + iqn = strsepq(&arg, delim); + else if (strcasecmp(subcmd, "LU") == 0) + lu_str = strsepq(&arg, delim); + else if (strcasecmp(subcmd, "ALL") == 0) + ; + else + err = 1; + } + if (arg != NULL || err == 1) { + istgt_uctl_snprintf(uctl, "ERR invalid parameters. usage: 'QUE IQN ' or 'QUE LU '\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_ERR; + } + if (lu_str != NULL) { + lu_num = (int) strtol(lu_str, NULL, 10); + } + + MTX_LOCK(&uctl->istgt->mutex); + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = uctl->istgt->logical_unit[i]; + if (lu == NULL) + continue; + if (iqn != NULL && strcasecmp(iqn, lu->name) != 0) + continue; + if (lu_num != -1 && lu->num != lu_num) + continue; + + if (lu->lun[0].type != ISTGT_LU_LUN_TYPE_STORAGE) + continue; + spec = (ISTGT_LU_DISK *) lu->lun[0].spec; + if (spec == NULL) + continue; + + levels = 24; + + clock_gettime(clockid, &now); + if(spec->do_avg == 0) + { + for(j=0;j<32;j++) + { + spec->avgs[j].count = 0; + spec->avgs[j].tot_sec = 0; + spec->avgs[j].tot_nsec = 0; + } + spec->do_avg = 1; + clock_gettime(clockid, &now1); + spec->avgs[0].tot_sec = now1.tv_sec; + spec->avgs[0].tot_nsec = now1.tv_nsec; + } + else + { + spec->do_avg = 0; + wn = snprintf(bptr, brem, " Avgs:"); + adjbuf() + if (((signed long)((signed long)(now.tv_nsec) - (signed long)(spec->avgs[0].tot_nsec))) < 0) { + spec->avgs[0].tot_sec = now.tv_sec - spec->avgs[0].tot_sec - 1; + spec->avgs[0].tot_nsec = 1000000000 + now.tv_nsec - spec->avgs[0].tot_nsec; + } else { + spec->avgs[0].tot_sec = now.tv_sec - spec->avgs[0].tot_sec; + spec->avgs[0].tot_nsec = now.tv_nsec - spec->avgs[0].tot_nsec; + } + + for(j=0;javgs[j].count, spec->avgs[j].tot_sec, + spec->avgs[j].tot_nsec); + adjbuf() + } + wn = snprintf(bptr, brem, " %d:%d", + j, spec->error_count); + adjbuf() + } + + inflight = spec->inflight; +// MTX_LOCK(&spec->cmd_queue_mutex); + cq = spec->cmd_queue.num; + bq = spec->blocked_queue.num; + inf = spec->ludsk_ref; +#if 0 + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->cmd_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + cookie = NULL; + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->blocked_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; +#endif +// MTX_UNLOCK(&spec->cmd_queue_mutex); + /* luworker waiting data from zvol */ +#if 0 + for (i=0; i < spec->luworkers; i++ ) { + MTX_LOCK(&spec->luworker_mutex[i]); + if(spec->inflight_io[i] != NULL) { + tdiff(spec->inflight_io[i]->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i, spec->inflight_io[i]->lu_cmd.CmdSN, + spec->inflight_io[i]->lu_cmd.cdb0, + spec->inflight_io[i]->lu_cmd.lba, + spec->inflight_io[i]->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + MTX_UNLOCK(&spec->luworker_mutex[i]); + } + //MTX_UNLOCK(&spec->cmd_queue_mutex); + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + /* luworker waiting data from network */ + MTX_LOCK(&spec->wait_lu_task_mutex); + for (i=0; i < ISTGT_MAX_NUM_LUWORKERS; i++ ) { + if (spec->wait_lu_task[i] != NULL) { + tdiff(spec->wait_lu_task[i]->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i, spec->wait_lu_task[i]->lu_cmd.CmdSN, + spec->wait_lu_task[i]->lu_cmd.cdb0, + spec->wait_lu_task[i]->lu_cmd.lba, + spec->wait_lu_task[i]->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + } + MTX_UNLOCK(&spec->wait_lu_task_mutex); +#endif + MTX_UNLOCK(&uctl->istgt->mutex); + unlocked = 1; + + ISTGT_TRACELOG(ISTGT_TRACE_CMD, + "LU%d:QUE %s %s Q[%d %d %d %d] q:%d thr:%d/%d [sz:%lu, %lu blks of %lu bytes, phy:%u %s%s] er_cnt:%d\n", + lu->num, lu->name ? lu->name : "-", (spec->fd != -1) ? "on" : "off", cq, bq, inf, inflight, + spec->queue_depth, spec->luworkers, spec->luworkersActive, + spec->size, spec->blockcnt, spec->blocklen, spec->rshift, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", spec->error_count); + + istgt_uctl_snprintf(uctl, + "%s LU%d:%s %s Q[%d %d %d %d] q:%d thr:%d/%d [sz:%lu, %lu blks of %lu bytes, phy:%u %s%s] er_cnt:%d\n", + uctl->cmd, lu->num, lu->name ? lu->name : "-", (spec->fd != -1) ? "on" : "off", cq, bq, inf, inflight, + spec->queue_depth, spec->luworkers, spec->luworkersActive, + spec->size, spec->blockcnt, spec->blocklen, spec->rshift, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", spec->error_count); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) + return rc; + + toprint = _BSZ_ - brem; + bptr = buf; + i = 0; + while(toprint > 0) + { + if (toprint > 1023) + chunk = 1024; + else + chunk = toprint; + ISTGT_TRACELOG(ISTGT_TRACE_CMD, + "LU%d:QUE%d [%.*s]\n", lu->num, i, chunk, bptr); + istgt_uctl_snprintf(uctl, + "%s LU%d:%d [%.*s]\n", uctl->cmd, lu->num, i, chunk, bptr); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) + return rc; + toprint -= chunk; + bptr += chunk; + ++i; + } + break; + } + if (unlocked == 0) { + MTX_UNLOCK(&uctl->istgt->mutex); + } + + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +extern _verb_istat ISCSIstat_rest[ISCSI_ARYSZ]; +extern _verb_stat SCSIstat_rest[SCSI_ARYSZ]; + +_verb_stat SCSIstat_last[SCSI_ARYSZ] = { {0,0,0} }; +_verb_stat SCSIstat_now[SCSI_ARYSZ] = { {0,0,0} }; +_verb_stat SCSIstat_rslt[SCSI_ARYSZ] = { {0,0,0} }; + +_verb_istat ISCSIstat_last[ISCSI_ARYSZ] = { {0,0,0} }; +_verb_istat ISCSIstat_now[ISCSI_ARYSZ] = { {0,0,0} }; +_verb_istat ISCSIstat_rslt[ISCSI_ARYSZ] = { {0,0,0} }; + +static int +istgt_uctl_cmd_stats(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + int rc; + int i; + char *zero = NULL; + int setzero = 0; + + int is_li = 0; + int s_li = 0; + _verb_istat is_l[ISCSI_ARYSZ]; + _verb_stat s_l[SCSI_ARYSZ]; + + arg = uctl->arg; + if (arg) + zero = strsepq(&arg, delim); + + if (zero != NULL) { + i = (int) strtol(zero, NULL, 10); + if (i == 1) + setzero = 1; + } + + bcopy(&ISCSIstat_rest, &ISCSIstat_now, sizeof(ISCSIstat_now)); + bcopy(&SCSIstat_rest, &SCSIstat_now, sizeof(SCSIstat_now)); + if (setzero == 1) { + for (i=0; i= ISCSIstat_last[i].pdu_read ? + ISCSIstat_now[i].pdu_read - ISCSIstat_last[i].pdu_read : + (0xffffffff - ISCSIstat_last[i].pdu_read) + ISCSIstat_now[i].pdu_read; + ISCSIstat_rslt[i].pdu_sent = + ISCSIstat_now[i].pdu_sent >= ISCSIstat_last[i].pdu_sent ? + ISCSIstat_now[i].pdu_sent - ISCSIstat_last[i].pdu_sent : + (0xffffffff - ISCSIstat_last[i].pdu_sent) + ISCSIstat_now[i].pdu_sent; + if (ISCSIstat_rslt[i].pdu_read || ISCSIstat_rslt[i].pdu_sent) { + is_l[is_li].opcode = ISCSIstat_now[i].opcode; + is_l[is_li].pdu_read = ISCSIstat_rslt[i].pdu_read; + is_l[is_li++].pdu_sent = ISCSIstat_rslt[i].pdu_sent; + } + } + for (i=0; i= SCSIstat_last[i].req_start ? + SCSIstat_now[i].req_start - SCSIstat_last[i].req_start : + (0xffffffff - SCSIstat_last[i].req_start) + SCSIstat_now[i].req_start; + SCSIstat_rslt[i].req_finish = + SCSIstat_now[i].req_finish >= SCSIstat_last[i].req_finish ? + SCSIstat_now[i].req_finish - SCSIstat_last[i].req_finish : + (0xffffffff - SCSIstat_last[i].req_finish) + SCSIstat_now[i].req_finish; + if (SCSIstat_rslt[i].req_start || SCSIstat_rslt[i].req_finish) { + s_l[s_li].opcode = SCSIstat_now[i].opcode; + s_l[s_li].req_start = SCSIstat_rslt[i].req_start; + s_l[s_li++].req_finish = SCSIstat_rslt[i].req_finish; + } + } + } else { + for (i=0; icmd, is_li, + is_l[0].opcode, is_l[0].pdu_read, is_l[0].pdu_sent, + is_l[1].opcode, is_l[1].pdu_read, is_l[1].pdu_sent, + is_l[2].opcode, is_l[2].pdu_read, is_l[2].pdu_sent, + is_l[3].opcode, is_l[3].pdu_read, is_l[3].pdu_sent, + is_l[4].opcode, is_l[4].pdu_read, is_l[4].pdu_sent, + is_l[5].opcode, is_l[5].pdu_read, is_l[5].pdu_sent, + is_l[6].opcode, is_l[6].pdu_read, is_l[6].pdu_sent, + is_l[7].opcode, is_l[7].pdu_read, is_l[7].pdu_sent, + is_l[8].opcode, is_l[8].pdu_read, is_l[8].pdu_sent, + is_l[9].opcode, is_l[9].pdu_read, is_l[9].pdu_sent); + rc = istgt_uctl_writeline(uctl); + + ISTGT_TRACELOG(ISTGT_TRACE_CMD, + "%s PDU:%d [%x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u]\n", + uctl->cmd, is_li, + is_l[0].opcode, is_l[0].pdu_read, is_l[0].pdu_sent, + is_l[1].opcode, is_l[1].pdu_read, is_l[1].pdu_sent, + is_l[2].opcode, is_l[2].pdu_read, is_l[2].pdu_sent, + is_l[3].opcode, is_l[3].pdu_read, is_l[3].pdu_sent, + is_l[4].opcode, is_l[4].pdu_read, is_l[4].pdu_sent, + is_l[5].opcode, is_l[5].pdu_read, is_l[5].pdu_sent, + is_l[6].opcode, is_l[6].pdu_read, is_l[6].pdu_sent, + is_l[7].opcode, is_l[7].pdu_read, is_l[7].pdu_sent, + is_l[8].opcode, is_l[8].pdu_read, is_l[8].pdu_sent, + is_l[9].opcode, is_l[9].pdu_read, is_l[9].pdu_sent); + if (rc != UCTL_CMD_OK) + return rc; + } + if (s_li) { + istgt_uctl_snprintf(uctl, "%s SCSI:%d [%x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u]\n", + uctl->cmd, s_li, + s_l[0].opcode, s_l[0].req_start, s_l[0].req_finish, + s_l[1].opcode, s_l[1].req_start, s_l[1].req_finish, + s_l[2].opcode, s_l[2].req_start, s_l[2].req_finish, + s_l[3].opcode, s_l[3].req_start, s_l[3].req_finish, + s_l[4].opcode, s_l[4].req_start, s_l[4].req_finish, + s_l[5].opcode, s_l[5].req_start, s_l[5].req_finish, + s_l[6].opcode, s_l[6].req_start, s_l[6].req_finish, + s_l[7].opcode, s_l[7].req_start, s_l[7].req_finish, + s_l[8].opcode, s_l[8].req_start, s_l[8].req_finish, + s_l[9].opcode, s_l[9].req_start, s_l[9].req_finish); + rc = istgt_uctl_writeline(uctl); + + ISTGT_TRACELOG(ISTGT_TRACE_CMD, "%s SCSI:%d [%x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u," + " %x:%u %u, %x:%u %u, %x:%u %u]\n", + uctl->cmd, s_li, + s_l[0].opcode, s_l[0].req_start, s_l[0].req_finish, + s_l[1].opcode, s_l[1].req_start, s_l[1].req_finish, + s_l[2].opcode, s_l[2].req_start, s_l[2].req_finish, + s_l[3].opcode, s_l[3].req_start, s_l[3].req_finish, + s_l[4].opcode, s_l[4].req_start, s_l[4].req_finish, + s_l[5].opcode, s_l[5].req_start, s_l[5].req_finish, + s_l[6].opcode, s_l[6].req_start, s_l[6].req_finish, + s_l[7].opcode, s_l[7].req_start, s_l[7].req_finish, + s_l[8].opcode, s_l[8].req_start, s_l[8].req_finish, + s_l[9].opcode, s_l[9].req_start, s_l[9].req_finish); + if (rc != UCTL_CMD_OK) + return rc; + } + if (!is_li && !s_li) { + istgt_uctl_snprintf(uctl, "%s PDU:0 SCSI:0 \n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) + return rc; + } + + istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + return UCTL_CMD_OK; +} + +typedef struct istgt_uctl_cmd_table_t +{ + const char *name; + int (*func) (UCTL_Ptr uctl); +} ISTGT_UCTL_CMD_TABLE; + +static ISTGT_UCTL_CMD_TABLE istgt_uctl_cmd_table[] = +{ + { "AUTH", istgt_uctl_cmd_auth }, + { "QUIT", istgt_uctl_cmd_quit }, + { "NOOP", istgt_uctl_cmd_noop }, + { "VERSION", istgt_uctl_cmd_version }, + { "LIST", istgt_uctl_cmd_list }, + { "UNLOAD", istgt_uctl_cmd_unload }, + { "LOAD", istgt_uctl_cmd_load }, + { "CHANGE", istgt_uctl_cmd_change }, + { "SYNC", istgt_uctl_cmd_sync }, + {"PERSIST", istgt_uctl_cmd_persist }, + { "RESET", istgt_uctl_cmd_reset }, + { "CLEAR", istgt_uctl_cmd_clear }, + { "REFRESH", istgt_uctl_cmd_refresh }, + { "START", istgt_uctl_cmd_start }, + { "STOP", istgt_uctl_cmd_stop }, + { "MODIFY", istgt_uctl_cmd_modify }, + { "STATUS", istgt_uctl_cmd_status }, + { "INFO", istgt_uctl_cmd_info }, + { "DUMP", istgt_uctl_cmd_dump }, + { "MEM", istgt_uctl_cmd_mem}, + { "MEMDEBUG", istgt_uctl_cmd_memdebug}, + { "LOG", istgt_uctl_cmd_log}, + { "RSV", istgt_uctl_cmd_rsv}, + { "QUE", istgt_uctl_cmd_que}, + { "STATS", istgt_uctl_cmd_stats}, + { "SET", istgt_uctl_cmd_set}, + { "MAXTIME", istgt_uctl_cmd_maxtime}, + { NULL, NULL }, +}; + +static int +istgt_uctl_cmd_execute(UCTL_Ptr uctl) +{ + int (*func) (UCTL_Ptr); + const char *delim = ARGS_DELIM; + char *arg; + char *cmd; + int rc; + int i; + + arg = trim_string(uctl->recvbuf); + cmd = strsepq(&arg, delim); + uctl->arg = arg; + uctl->cmd = strupr(cmd); + + func = NULL; + for (i = 0; istgt_uctl_cmd_table[i].name != NULL; i++) { + if (cmd[0] == istgt_uctl_cmd_table[i].name[0] + && strcmp(cmd, istgt_uctl_cmd_table[i].name) == 0) { + func = istgt_uctl_cmd_table[i].func; + break; + } + } + if (func == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "uctl_cmd:%d ERR unknown command\n", i); + istgt_uctl_snprintf(uctl, "ERR unknown command\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return UCTL_CMD_DISCON; + } + return UCTL_CMD_ERR; + } + + if (uctl->no_auth + && (strcasecmp(cmd, "AUTH") == 0)) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "uctl_cmd:%d ERR auth not requried\n", i); + istgt_uctl_snprintf(uctl, "ERR auth not required\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return UCTL_CMD_DISCON; + } + return UCTL_CMD_ERR; + } + if (uctl->req_auth && uctl->authenticated == 0 + && !(strcasecmp(cmd, "QUIT") == 0 + || strcasecmp(cmd, "AUTH") == 0)) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "uctl_cmd:%d ERR auth requried\n", i); + istgt_uctl_snprintf(uctl, "ERR auth required\n"); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return UCTL_CMD_DISCON; + } + return UCTL_CMD_ERR; + } + + ISTGT_TRACELOG(ISTGT_TRACE_NET, "uctl_cmd: %d:%s executing\n", i, istgt_uctl_cmd_table[i].name); + rc = func(uctl); + return rc; +} + +static void istgt_free_uctl(UCTL_Ptr uctl); + +static void * +uctlworker(void *arg) +{ + UCTL_Ptr uctl = (UCTL_Ptr) arg; + int rc; + pthread_t self = pthread_self(); + snprintf(tinfo, sizeof tinfo, "u#%d.%ld", uctl->sock, (uint64_t)(((uint64_t *)self)[0])); +#ifdef HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(pthread_self(), tinfo); +#endif + + ISTGT_TRACELOG(ISTGT_TRACE_NET, "connect to %s:%s,%d (%s->%s)\n", + uctl->portal.host, uctl->portal.port, uctl->portal.tag, uctl->caddr, uctl->saddr); + + istgt_uctl_snprintf(uctl, "iSCSI Target Controller version %s" + " on %s from %s\n", + istgtvers, + uctl->saddr, uctl->caddr); + rc = istgt_uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + ISTGT_ERRLOG("uctl_writeline() failed\n"); + return NULL; + } + + while (1) { + if (istgt_get_state(uctl->istgt) != ISTGT_STATE_RUNNING) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "uctl_.. not running..\n"); + break; + } + + /* read from socket */ + rc = istgt_uctl_readline(uctl); + if (rc == UCTL_CMD_EOF) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "uctl_readline() EOF\n"); + break; + } + if (rc != UCTL_CMD_OK) { + ISTGT_ERRLOG("uctl_readline() failed\n"); + break; + } + /* execute command */ + rc = istgt_uctl_cmd_execute(uctl); + if (rc == UCTL_CMD_QUIT) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "receive QUIT\n"); + break; + } + if (rc == UCTL_CMD_DISCON) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "request disconnect\n"); + break; + } + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "exiting ctlworker\n"); + + close(uctl->sock); + uctl->sock = -1; + istgt_free_uctl(uctl); + return NULL; +} + +static void +istgt_free_uctl(UCTL_Ptr uctl) +{ + if (uctl == NULL) + return; + xfree(uctl->mediadirectory); + xfree(uctl->portal.label); + xfree(uctl->portal.host); + xfree(uctl->portal.port); + xfree(uctl->auth.user); + xfree(uctl->auth.secret); + xfree(uctl->auth.muser); + xfree(uctl->auth.msecret); + xfree(uctl); +} + +int +istgt_create_uctl(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen __attribute__((__unused__))) +{ + char buf[MAX_TMPBUF]; + UCTL_Ptr uctl; + int rc; + int i; + + uctl = xmalloc(sizeof *uctl); + memset(uctl, 0, sizeof *uctl); + + uctl->istgt = istgt; + MTX_LOCK(&istgt->mutex); + uctl->auth_group = istgt->uctl_auth_group; + uctl->no_auth = istgt->no_uctl_auth; + uctl->req_auth = istgt->req_uctl_auth; + uctl->req_mutual = istgt->req_uctl_auth_mutual; + uctl->mediadirectory = xstrdup(istgt->mediadirectory); + MTX_UNLOCK(&istgt->mutex); + + uctl->portal.label = xstrdup(portal->label); + uctl->portal.host = xstrdup(portal->host); + uctl->portal.port = xstrdup(portal->port); + uctl->portal.tag = portal->tag; + uctl->portal.sock = -1; + uctl->sock = sock; + + uctl->timeout = TIMEOUT_RW; + uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A; + uctl->auth.user = NULL; + uctl->auth.secret = NULL; + uctl->auth.muser = NULL; + uctl->auth.msecret = NULL; + uctl->authenticated = 0; + + uctl->recvtmpcnt = 0; + uctl->recvtmpidx = 0; + uctl->recvtmpsize = sizeof uctl->recvtmp; + uctl->recvbufsize = sizeof uctl->recvbuf; + uctl->sendbufsize = sizeof uctl->sendbuf; + uctl->worksize = sizeof uctl->work; + + memset(uctl->caddr, 0, sizeof uctl->caddr); + memset(uctl->saddr, 0, sizeof uctl->saddr); + + switch (sa->sa_family) { + case AF_INET6: + uctl->family = AF_INET6; + rc = istgt_getaddr(sock, uctl->saddr, sizeof uctl->saddr, + uctl->caddr, sizeof uctl->caddr, &uctl->iaddr, (uint16_t *)&uctl->iport); + if (rc < 0) { + ISTGT_ERRLOG("istgt_getaddr() failed\n"); + goto error_return; + } + break; + case AF_INET: + uctl->family = AF_INET; + rc = istgt_getaddr(sock, uctl->saddr, sizeof uctl->saddr, + uctl->caddr, sizeof uctl->caddr, &uctl->iaddr, (uint16_t *)&uctl->iport); + if (rc < 0) { + ISTGT_ERRLOG("istgt_getaddr() failed\n"); + goto error_return; + } + break; + case AF_UNIX: + uctl->family = AF_UNIX; + break; + default: + ISTGT_ERRLOG("unsupported family\n"); + goto error_return; + } + + if (istgt->nuctl_netmasks != 0 && (uctl->family != AF_UNIX)) { + rc = -1; + for (i = 0; i < istgt->nuctl_netmasks; i++) { + rc = istgt_lu_allow_netmask(istgt->uctl_netmasks[i], uctl->caddr); + if (rc > 0) { + /* OK netmask */ + break; + } + } + if (rc <= 0) { + ISTGT_WARNLOG("UCTL access denied from %s to (%s:%s)\n", + uctl->caddr, uctl->portal.host, uctl->portal.port); + goto error_return; + } + } + + printf("sock=%d, addr=%s, peer=%s\n", + sock, uctl->saddr, + uctl->caddr); + + /* wildcard? */ + if (uctl->family != AF_UNIX) { + if (strcasecmp(uctl->portal.host, "[::]") == 0 + || strcasecmp(uctl->portal.host, "[*]") == 0) { + if (uctl->family != AF_INET6) { + ISTGT_ERRLOG("address family error\n"); + goto error_return; + } + snprintf(buf, sizeof buf, "[%s]", uctl->caddr); + xfree(uctl->portal.host); + uctl->portal.host = xstrdup(buf); + } else if (strcasecmp(uctl->portal.host, "0.0.0.0") == 0 + || strcasecmp(uctl->portal.host, "*") == 0) { + if (uctl->family != AF_INET) { + ISTGT_ERRLOG("address family error\n"); + goto error_return; + } + snprintf(buf, sizeof buf, "%s", uctl->caddr); + xfree(uctl->portal.host); + uctl->portal.host = xstrdup(buf); + } + } + + /* set timeout msec. */ + rc = istgt_set_recvtimeout(uctl->sock, uctl->timeout * 1000); + if (rc != 0) { + ISTGT_ERRLOG("istgt_set_recvtimeo() failed\n"); + goto error_return; + } + rc = istgt_set_sendtimeout(uctl->sock, uctl->timeout * 1000); + if (rc != 0) { + ISTGT_ERRLOG("istgt_set_sendtimeo() failed\n"); + goto error_return; + } + + /* create new thread */ +#ifdef ISTGT_STACKSIZE + rc = pthread_create(&uctl->thread, &istgt->attr, &uctlworker, (void *)uctl); +#else + rc = pthread_create(&uctl->thread, NULL, &uctlworker, (void *)uctl); +#endif + if (rc != 0) { + ISTGT_ERRLOG("pthread_create() failed\n"); + error_return: + xfree(uctl->portal.label); + xfree(uctl->portal.host); + xfree(uctl->portal.port); + xfree(uctl); + return -1; + } + rc = pthread_detach(uctl->thread); + if (rc != 0) { + ISTGT_ERRLOG("pthread_detach() failed\n"); + goto error_return; + } + return 0; +} + +int +istgt_uctl_init(ISTGT_Ptr istgt) +{ + CF_SECTION *sp; + const char *val; + const char *ag_tag; + int alloc_len; + int ag_tag_i; + int masks; + int i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init_uctl_section\n"); + + sp = istgt_find_cf_section(istgt->config, "UnitControl"); + if (sp == NULL) { + ISTGT_ERRLOG("find_cf_section failed()\n"); + return -1; + } + + val = istgt_get_val(sp, "Comment"); + if (val != NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val); + } + + for (i = 0; ; i++) { + val = istgt_get_nval(sp, "Netmask", i); + if (val == NULL) + break; + } + masks = i; + if (masks > MAX_NETMASK) { + ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks); + return -1; + } + istgt->nuctl_netmasks = masks; + alloc_len = sizeof (char *) * masks; + istgt->uctl_netmasks = xmalloc(alloc_len); + for (i = 0; i < masks; i++) { + val = istgt_get_nval(sp, "Netmask", i); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val); + istgt->uctl_netmasks[i] = xstrdup(val); + } + + val = istgt_get_val(sp, "AuthMethod"); + if (val == NULL) { + istgt->no_uctl_auth = 0; + istgt->req_uctl_auth = 0; + } else { + istgt->no_uctl_auth = 0; + for (i = 0; ; i++) { + val = istgt_get_nmval(sp, "AuthMethod", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "CHAP") == 0) { + istgt->req_uctl_auth = 1; + } else if (strcasecmp(val, "Mutual") == 0) { + istgt->req_uctl_auth_mutual = 1; + } else if (strcasecmp(val, "Auto") == 0) { + istgt->req_uctl_auth = 0; + istgt->req_uctl_auth_mutual = 0; + } else if (strcasecmp(val, "None") == 0) { + istgt->no_uctl_auth = 1; + istgt->req_uctl_auth = 0; + istgt->req_uctl_auth_mutual = 0; + } else { + ISTGT_ERRLOG("unknown auth\n"); + return -1; + } + } + } + if (istgt->no_uctl_auth == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n"); + } else if (istgt->req_uctl_auth == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n", + istgt->req_uctl_auth ? "CHAP" : "", + istgt->req_uctl_auth_mutual ? "Mutual" : ""); + } + + val = istgt_get_val(sp, "AuthGroup"); + if (val == NULL) { + istgt->uctl_auth_group = 0; + } else { + ag_tag = val; + if (strcasecmp(ag_tag, "None") == 0) { + ag_tag_i = 0; + } else { + if (strncasecmp(ag_tag, "AuthGroup", + strlen("AuthGroup")) != 0 + || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) { + ISTGT_ERRLOG("auth group error\n"); + return -1; + } + if (ag_tag_i == 0) { + ISTGT_ERRLOG("invalid auth group %d\n", ag_tag_i); + return -1; + } + } + istgt->uctl_auth_group = ag_tag_i; + } + if (istgt->uctl_auth_group == 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup None\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup AuthGroup%d\n", + istgt->uctl_auth_group); + } + + return 0; +} + +int +istgt_uctl_shutdown(ISTGT_Ptr istgt) +{ + int i; + + for (i = 0; i < istgt->nuctl_netmasks; i++) { + xfree(istgt->uctl_netmasks[i]); + } + xfree(istgt->uctl_netmasks); + return 0; +} diff --git a/src/istgt_lu_disk.c b/src/istgt_lu_disk.c new file mode 100644 index 00000000..8bbecdec --- /dev/null +++ b/src/istgt_lu_disk.c @@ -0,0 +1,10729 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include + +#include +#include +#include + +#ifdef HAVE_UUID_H +#include +#endif + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_conf.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_crc32c.h" +#include "istgt_md5.h" +#include "istgt_iscsi.h" +#include "istgt_iscsi_xcopy.h" +#include "istgt_lu.h" +#include "istgt_proto.h" +#include "istgt_scsi.h" +#include "istgt_queue.h" + +#ifdef __FreeBSD__ +#include +#endif + +#include + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#ifndef O_FSYNC +#define O_FSYNC O_SYNC +#endif + +extern clockid_t clockid; +//#define ISTGT_TRACE_DISK + +#define timesdiffX(_st, _now, _re) \ +{ \ + if (_now.tv_sec == 0) { \ + _now.tv_sec = _st.tv_sec; _now.tv_nsec = _st.tv_nsec; \ + } \ + if ((_now.tv_nsec - _st.tv_nsec)<0) { \ + _re.tv_sec = _now.tv_sec - _st.tv_sec - 1; \ + _re.tv_nsec = 1000000000 + _now.tv_nsec - _st.tv_nsec; \ + } else { \ + _re.tv_sec = _now.tv_sec - _st.tv_sec; \ + _re.tv_nsec = _now.tv_nsec - _st.tv_nsec; \ + } \ +} + +#define timesdiff(_st, _now, _re) \ +{ \ + clock_gettime(clockid, &_now); \ + if ((_now.tv_nsec - _st.tv_nsec)<0) { \ + _re.tv_sec = _now.tv_sec - _st.tv_sec - 1; \ + _re.tv_nsec = 1000000000 + _now.tv_nsec - _st.tv_nsec; \ + } else { \ + _re.tv_sec = _now.tv_sec - _st.tv_sec; \ + _re.tv_nsec = _now.tv_nsec - _st.tv_nsec; \ + } \ +} + +#define MAX_DIO_WAIT 30 //loop for 30 seconds +//#define enterblockingcall(lu_cmd, conn) +#define enterblockingcall(macroname) \ +{ \ + lu_cmd->connGone = 0; \ + if(pthread_mutex_lock(&spec->state_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ + if (spec->state == ISTGT_LUN_BUSY) { \ + lu_cmd->data_len = 0; \ + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; \ + if(pthread_mutex_unlock(&spec->state_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ + return 0; \ + } \ + ++(spec->ludsk_ref); \ + if(pthread_mutex_unlock(&spec->state_mutex) != 0) \ + { \ + --(spec->ludsk_ref); \ + markedForReturn = 1; \ + goto macroname; \ + } \ + if(pthread_mutex_lock(&conn->diskioflag_mutex) != 0) \ + { \ + --(spec->ludsk_ref); \ + markedForReturn = 1; \ + goto macroname; \ + } \ + ++(conn->diskIoPending); \ + if(pthread_mutex_unlock(&conn->diskioflag_mutex) != 0) \ + { \ + --(conn->diskIoPending); \ + --(spec->ludsk_ref); \ + markedForReturn = 1; \ + goto macroname; \ + } \ +} \ +macroname: + +//#define exitblockingcall(lu_cmd, conn, diskIoPendingL, markedForFree) +#define exitblockingcall(macroname) \ +{ \ + if(pthread_mutex_lock(&spec->state_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ + --(spec->ludsk_ref); \ + if(pthread_mutex_unlock(&spec->state_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ + if(pthread_mutex_lock(&conn->diskioflag_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ + --(conn->diskIoPending); \ + diskIoPendingL = conn->diskIoPending; \ + if (conn->flagDelayedFree == 1) \ + markedForFree = 1; \ + if(pthread_mutex_unlock(&conn->diskioflag_mutex) != 0) \ + { \ + markedForReturn = 1; \ + goto macroname; \ + } \ +} \ +macroname: + +#define create_time times[0] + +#define errlog(lu_cmd, fmt, ...) \ +{ \ + syslog(LOG_ERR, "%-18.18s:%4d: %-8.8s: [%u.%x lba%lu+%u %c.%ld.%ld %c.%ld.%ld]" fmt, \ + __func__, __LINE__, tinfo, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lba, lu_cmd->lblen, \ + lu_cmd->caller[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0], \ + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_sec, \ + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_nsec, \ + lu_cmd->caller[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0], \ + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_sec, \ + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_nsec, \ + ##__VA_ARGS__); \ +} + +typedef enum { + ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE = 0x01, + ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS = 0x03, + ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY = 0x05, + ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY = 0x06, + ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS = 0x07, + ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS = 0x08, +} ISTGT_LU_PR_TYPE; + +#define PR_ALLOW(WE,EA,ALLRR,WERR,EARR) \ + ((((WE)&1) << 4) | (((EA)&1) << 3) | (((ALLRR)&1) << 2) \ + | (((WERR)&1) << 1) | (((EARR)&1) << 0)) +#define PR_ALLOW_WE 0x0010 +#define PR_ALLOW_EA 0x0008 +#define PR_ALLOW_ALLRR 0x0004 +#define PR_ALLOW_WERR 0x0002 +#define PR_ALLOW_EARR 0x0001 + +#define BUILD_SENSE(SK,ASC,ASCQ) istgt_lu_scsi_build_sense_data(lu_cmd,ISTGT_SCSI_SENSE_ ## SK, (ASC), (ASCQ)) +#define BUILD_SENSE2(SK,ASC,ASCQ) istgt_lu_scsi_build_sense_data2(lu_cmd, ISTGT_SCSI_SENSE_ ## SK, (ASC), (ASCQ)) + +static int istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port); + static const char * +istgt_get_disktype_by_ext(const char *file); +static int istgt_lu_disk_unmap(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data, int pllen); +int istgt_lu_disk_copy_reservation(ISTGT_LU_DISK *spec_bkp, ISTGT_LU_DISK *spec); + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit + */ + +static inline long +find_first_bit(ISTGT_LU_CMD_Ptr lu_cmd) +{ + long d0, d1; + long res, res_final=0; + int iovcnt, i; + uint64_t nbytes; + unsigned long nbits = 0; + const unsigned long * addr; + iovcnt = lu_cmd->iobufindx+1; + for (i=0; i < iovcnt; ++i) { + addr = (const unsigned long *)lu_cmd->iobuf[i].iov_base; + nbytes = lu_cmd->iobuf[i].iov_len; + nbits = nbytes << 3; + nbits += 63; + nbits >>= 6; + if (!nbits) + continue; + asm volatile( + " repe; scasq\n" + " jz 1f\n" + " subq $8,%%rdi\n" + " bsfq (%%rdi),%%rax\n" + "1: subq %[addr],%%rdi\n" + " shlq $3,%%rdi\n" + " addq %%rdi,%%rax" + :"=a" (res), "=&c" (d0), "=&D" (d1) + :"0" (0ULL), "1" (nbits), "2" (addr), + [addr] "r" (addr) : "memory"); + res_final +=res; + if((unsigned long)res != nbits) + return res_final; + } + return res_final; +} +static int +istgt_lu_disk_open_raw(ISTGT_LU_DISK *spec, int flags, int mode) +{ + int rc; + errno = 0; + rc = open(spec->file, flags, mode); + spec->fderr = rc; + spec->fderrno = errno; + if (rc < 0) { + return -1; + } + spec->fd = rc; + spec->foffset = 0; + return 0; +} + +int +istgt_lu_disk_close_raw(ISTGT_LU_DISK *spec) +{ + int rc; + + if (spec->fd == -1) + return 0; + rc = close(spec->fd); + if (rc < 0) { + return -1; + } + spec->fd = -1; + spec->foffset = 0; + return 0; +} + +static int64_t +istgt_lu_disk_seek_raw(ISTGT_LU_DISK *spec, uint64_t offset) +{ + off_t rc; + + rc = lseek(spec->fd, (off_t) offset, SEEK_SET); + if (rc < 0) { + return -1; + } + spec->foffset = offset; + return 0; +} + +static int64_t +istgt_lu_disk_sync_raw(ISTGT_LU_DISK *spec, uint64_t offset, uint64_t nbytes) +{ + int64_t rc; + + rc = (int64_t) fsync(spec->fd); + if (rc < 0) { + return -1; + } + spec->foffset = offset + nbytes; + return rc; +} + +int +istgt_lu_disk_signal_action(ISTGT_LU_Ptr lu, int i, struct timespec *now, istgt_action act) +{ + ISTGT_LU_DISK *spec; + int rc; + int signal_worker = 0; + const char *action = (act == ACTION_CLOSE ) ? "close" : "open"; + istgt_lun_state st, st1; + istgt_lun_ex_state exst, exst1; + const char *path = ""; + + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); + lu->lun[i].spec = NULL; + return -1; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + spec = lu->lun[i].spec; + if (spec == NULL) { + ISTGT_NOTICELOG("LU%d: LUN%d spec is found\n", lu->num, i); + return -1; + } + + MTX_LOCK(&spec->state_mutex); + st = spec->state; + exst = spec->ex_state; + if (act == ACTION_CLOSE) { + spec->state = ISTGT_LUN_BUSY; + if (spec->ex_state < ISTGT_LUN_CLOSE_PENDING) { + spec->ex_state = ISTGT_LUN_CLOSE_PENDING; + spec->close_started.tv_sec = now->tv_sec; + spec->close_started.tv_nsec = now->tv_nsec; + signal_worker = 1; + } else if ((spec->ex_state == ISTGT_LUN_CLOSE_PENDING) || (spec->ludsk_ref != 0)) { + signal_worker = 1; + } + } else if (act == ACTION_OPEN) { + if (spec->ex_state > ISTGT_LUN_OPEN) { + if (spec->ex_state < ISTGT_LUN_CLOSE) { + spec->open_waiting4close = 1; //open after the pending close + path = "open_after_pending_close"; + } else { + spec->ex_state = ISTGT_LUN_OPEN_PENDING; + } + spec->open_started.tv_sec = now->tv_sec; + spec->open_started.tv_nsec = now->tv_nsec; + signal_worker = 1; + } else if (spec->ex_state == ISTGT_LUN_OPEN_PENDING) { + signal_worker = 1; + } + } + st1 = spec->state; + exst1 = spec->ex_state; + MTX_UNLOCK(&spec->state_mutex); + lu->limit_q_size=0; + + if (signal_worker == 1) { + /* notify LUN thread */ + MTX_LOCK(&spec->complete_queue_mutex); + spec->disk_modify_work_pending = 1; + rc = pthread_cond_signal(&spec->maint_cmd_queue_cond); + MTX_UNLOCK(&spec->complete_queue_mutex); + + if (rc != 0) { + ISTGT_ERRLOG("cond signal failed ,lun %d, rc = %d \n", + lu->num, rc); + return -1; + } + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d %s %s %s state:%d/%d %d/%d \n", + lu->num, i, action, + signal_worker == 1 ? "signal" : "skip", path, + st, st1, exst, exst1); + return signal_worker; +} + +int +istgt_lu_disk_close(ISTGT_LU_Ptr lu, int i) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + int rc; + int disk_ref = 0; + int workers_signaled = 0; + struct timespec _s1, _s2, _s3, _wrk, _wrkx, cur_time; + + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", lu->num, i); + lu->lun[i].spec = NULL; + return -1; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + spec = lu->lun[i].spec; + if (spec == NULL) { + ISTGT_NOTICELOG("LU%d: LUN%d spec is not found\n", lu->num, i); + return -1; + } + + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + if (spec->ludsk_ref == 0) + workers_signaled = 1; + if (workers_signaled == 0) { + clock_gettime(clockid, &cur_time); + if(cur_time.tv_sec - spec->close_started.tv_sec < 170) { + MTX_UNLOCK(&spec->state_mutex); + return -1; + } + } + spec->ex_state = ISTGT_LUN_CLOSE_INPROGRESS; + MTX_UNLOCK(&spec->state_mutex); + disk_ref = spec->ludsk_ref; + + timesdiff(spec->close_started, _wrkx, _s1) + if (!spec->lu->readonly) { + rc = spec->sync(spec, 0, spec->size); + timesdiff(_wrkx, _wrk, _s2) + if (rc < 0) { + /* Ignore error */ + ISTGT_ERRLOG("LU%d: LUN%d: failed to sync\n", lu->num, i); + } + } else { + _wrk.tv_sec = _wrkx.tv_sec; + _wrk.tv_nsec = _wrkx.tv_nsec; + _s2.tv_sec = 0; _s2.tv_nsec = 0; + } + rc = spec->close(spec); + timesdiff(_wrk, _wrkx, _s3) + if (rc < 0) { + /* Ignore error */ + ISTGT_ERRLOG("LU%d: LUN%d failed to close device\n", lu->num, i); + } + lu->lun[i].u.storage.fd = -1; + spec->fd = -1; + + MTX_LOCK(&spec->pr_rsv_mutex); + /* release reservation */ + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->spc2_reserved = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + + /* remove all registrations */ + for (i = 0; i < spec->npr_keys; i++) { + istgt_lu_disk_free_pr_key(&spec->pr_keys[i]); + } + spec->npr_keys = 0; + for (i = 0; i < MAX_LU_RESERVE; i++) { + memset(&spec->pr_keys[i], 0, sizeof(spec->pr_keys[i])); + } + MTX_UNLOCK(&spec->pr_rsv_mutex); + + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + nexus->ua_pending &= ISTGT_UA_NONE; + } + MTX_LOCK(&spec->state_mutex); + spec->ex_state = ISTGT_LUN_CLOSE; + MTX_UNLOCK(&spec->state_mutex); + lu->limit_q_size = 0; + + ISTGT_LOG("LU%d: LUN%d %s: storage_offline, holds:%d [%ld.%ld - %ld.%ld - %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", disk_ref, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec, _s3.tv_sec, _s3.tv_nsec); + return 0; +} + +int +istgt_lu_disk_post_open(ISTGT_LU_DISK *spec) +{ + ISTGT_LU_Ptr lu; + int i; + int rc = 0; + int errorno = 0; + + lu = spec->lu; + i = spec->lun; + if (!lu->readonly) { + rc = spec->allocate(spec); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n", + lu->num, i); + errorno = errno; + goto error_return; + } + } + if (spec->rsize == 0) { + //TODO + #ifdef __FreeBSD__ + off_t rsize = 0; + uint32_t lbPerRecord = 0; + rc = ioctl(spec->fd, DIOCGSTRIPESIZE, &rsize); + if (rc != -1) { + ISTGT_ERRLOG("LU%d: LUN%d: ioctl-blksize:%lu \n", lu->num, i, rsize); + spec->rsize = rsize; + if (spec->rsize > spec->blocklen) { + lbPerRecord = spec->rsize / ((uint32_t)(spec->blocklen)); + spec->lb_per_rec = lbPerRecord; + spec->rshiftreal = fls(lbPerRecord) - 1; + if (lbPerRecord & (lbPerRecord-1)) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen:%lu zfsrecordSize:%u\n", + lu->num, i, spec->blocklen, spec->rsize); + } + } + } else { + ISTGT_ERRLOG("LU%d: LUN%d: ioctl-blksize:%lu failed:%d %d\n", lu->num, i, rsize, rc, errno); + } + #endif + } + rc = spec->setcache(spec); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: setcache error\n", lu->num, i); + errorno = errno; + goto error_return; + } + if(spec->persist){ + ISTGT_LOG("READING RESERVATIONS FROM ZAP"); + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_get_reservation(spec); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (rc < 0) { + ISTGT_ERRLOG("istgt_lu_disk_get_reservation() failed errno %d\n", rc); + errorno = errno; + goto error_return; + } + } + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_ONLINE; + spec->ex_state = ISTGT_LUN_OPEN; + MTX_UNLOCK(&spec->state_mutex); + ISTGT_LOG("Completed successfully post open for LU%d\n", lu->num); +error_return: + return errorno; +} + +int +istgt_lu_disk_open(ISTGT_LU_Ptr lu, int i) +{ + ISTGT_LU_DISK *spec; + uint64_t gb_size; + uint64_t mb_size; + int flags; + int rc; + uint32_t lbPerRecord = 0; + uint32_t old_rsize; + uint64_t old_size; + uint64_t old_blockcnt; + uint64_t old_blocklen; + uint32_t old_lb_per_rec, old_rshift; + uint16_t old_opt_tlen; + struct timespec _s1, _s2, _wrk, _wrkx; + int rpm; + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); + lu->lun[i].spec = NULL; + return -1; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + + spec = lu->lun[i].spec; + if (spec == NULL) { + ISTGT_NOTICELOG("LU%d: LUN%d spec is found\n", lu->num, i); + return -1; + } + + _wrk.tv_sec = spec->open_started.tv_sec; + _wrk.tv_nsec = spec->open_started.tv_nsec; + + timesdiff(_wrk, _wrkx, _s1) + old_rsize = spec->rsize; + old_size = spec->size; + old_blocklen = spec->blocklen; + old_blockcnt = spec->blockcnt; + old_lb_per_rec = spec->lb_per_rec; + old_rshift = spec->rshiftreal; + old_opt_tlen = spec->opt_tlen; + spec->luworkers = lu->luworkers; + spec->luworkersActive = lu->luworkersActive; + spec->file = lu->lun[i].u.storage.file; + spec->size = lu->lun[i].u.storage.size; + spec->rsize = lu->lun[i].u.storage.rsize; + spec->disktype = istgt_get_disktype_by_ext(spec->file); + spec->blocklen = 0; + spec->blockcnt = 0; + spec->lb_per_rec = 1; + spec->opt_tlen = (uint16_t)lu->lun[i].opt_tlen; + spec->rshift = (uint32_t)lu->rshift; + spec->rshiftreal = 0; + rpm = lu->lun[i].rotationrate; + if (strcasecmp(spec->disktype, "RAW") == 0) { + spec->blocklen = lu->blocklen; + if (spec->blocklen != 512 && + spec->blocklen != 1024 && + spec->blocklen != 2048 && + spec->blocklen != 4096 && + spec->blocklen != 8192 && + spec->blocklen != 16384 && + spec->blocklen != 32768 && + spec->blocklen != 65536 && + spec->blocklen != 131072 && + spec->blocklen != 262144 && + spec->blocklen != 524288) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen %"PRIu64"\n", + lu->num, i, spec->blocklen); + goto error_return; + } + spec->blockcnt = spec->size / spec->blocklen; + if (spec->blockcnt == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: size zero\n", lu->num, i); + goto error_return; + } + if (spec->rsize > spec->blocklen) { + lbPerRecord = spec->rsize / ((uint32_t)(spec->blocklen)); + spec->lb_per_rec = lbPerRecord; + spec->rshiftreal = fls(lbPerRecord) - 1; + if (lbPerRecord & (lbPerRecord-1)) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen:%lu zfsrecordSize:%u\n", + lu->num, i, spec->blocklen, spec->rsize); + } + } + + if (spec->fd > -1){ + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + MTX_UNLOCK(&spec->state_mutex); + rc = spec->close(spec); + if (rc < 0) { + /* Ignore error */ + ISTGT_ERRLOG("LU%d: LUN%d failed to close device\n", lu->num, i); + goto error_return; + } //else { + // MTX_LOCK(&spec->state_mutex); + // spec->ex_state = ISTGT_LUN_CLOSE; + // MTX_UNLOCK(&spec->state_mutex); + //} + + } + + spec->fd = -1; + lu->lun[i].u.storage.fd = -1; + lu->limit_q_size = 0; + + flags = lu->readonly ? O_RDONLY : O_RDWR; + rc = spec->open(spec, flags, 0666); + timesdiff(_wrkx, _wrk, _s2) + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d/%d)[%s]\n", + lu->num, i, spec->fderr, spec->fderrno, spec->file); + flags = lu->readonly ? O_RDONLY : (O_CREAT | O_EXCL | O_RDWR); + rc = spec->open(spec, flags, 0666); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d/%d)[%s]\n", + lu->num, i, spec->fderr, spec->fderrno, spec->file); + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + spec->ex_state = ISTGT_LUN_NOTYET; + MTX_UNLOCK(&spec->state_mutex); + goto error_return; + } + } + MTX_LOCK(&spec->pr_rsv_mutex); + spec->rsv_pending |= ISTGT_RSV_READ; + MTX_UNLOCK(&spec->pr_rsv_mutex); + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + spec->ex_state = ISTGT_LUN_OPEN; + MTX_UNLOCK(&spec->state_mutex); + + gb_size = spec->size / ISTGT_LU_1GB; + mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB; + printf("LU%d: LUN%d %s: storage_onlinex %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u/%u %s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d [%ld.%ld, %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, spec->rshiftreal, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + rpm, spec->queue_depth, spec->luworkers, spec->luworkersActive, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec); + ISTGT_LOG("LU%d: LUN%d %s: storage_onlinex %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u/%u %s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d [%ld.%ld, %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, spec->rshiftreal, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + rpm, spec->queue_depth, spec->luworkers, spec->luworkersActive, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec); + + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unsupported format\n", lu->num, i); + goto error_return; + } + + lu->lun[i].spec = spec; + return 0; +error_return: + spec->rsize = old_rsize; + spec->size = old_size; + spec->blockcnt = old_blockcnt; + spec->blocklen = old_blocklen; + spec->lb_per_rec = old_lb_per_rec; + spec->rshiftreal = old_rshift; + spec->opt_tlen = old_opt_tlen; + return -1; +} + + +static int +istgt_lu_disk_allocate_raw(ISTGT_LU_DISK *spec) +{ + uint8_t *data; + uint64_t fsize; + uint64_t size; + uint64_t blocklen; + uint64_t offset; + uint64_t nbytes; + int64_t rc; + + size = spec->size; + blocklen = spec->blocklen; + nbytes = blocklen; + data = xmalloc(nbytes); + memset(data, 0, nbytes); + + fsize = istgt_lu_get_filesize(spec->file); + if (fsize > size) { /* case when quota is reduced */ + xfree(data); + return 0; + } + spec->fsize = fsize; + + offset = size - nbytes; + + rc = pread(spec->fd, data, nbytes, offset); + /* EOF is OK */ + if (rc < 0) { + ISTGT_ERRLOG("lu_disk_read() failed:errno:%d\n", errno); + xfree(data); + return -1; + } + + /* allocate complete size */ + /*This can be avoided since thin provisioned volume of this size has already been created*/ + /* + rc = pwrite(spec->fd, data, nbytes, offset); + if (rc < 0 || (uint64_t) rc != nbytes) { + ISTGT_ERRLOG("lu_disk_write() failed:errno:%d written:%ld\n", errno, rc); + xfree(data); + return -1; + } + */ + spec->foffset = size; + + xfree(data); + return 0; +} + +static int +istgt_lu_disk_setcache_raw(ISTGT_LU_DISK *spec) +{ + int flags; + int rc; + int fd; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_setcache\n"); + + fd = spec->fd; + if (spec->readcache) { + /* not implement */ + } else { + /* not implement */ + } + flags = fcntl(fd , F_GETFL, 0); + if (flags != -1) { + if (spec->writecache) { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "write cache enable\n"); + rc = fcntl(fd, F_SETFL, (flags & ~O_FSYNC)); + spec->writecache = 1; + } else { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "write cache disable\n"); + rc = fcntl(fd, F_SETFL, (flags | O_FSYNC)); + spec->writecache = 0; + } + if (rc == -1) { +#if 0 + ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_SETFL) failed(errno=%d)\n", + spec->num, spec->lun, errno); +#endif + } + } else { + ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_GETFL) failed(errno=%d)\n", + spec->num, spec->lun, errno); + } + return 0; +} + +static const char * +istgt_get_disktype_by_ext(const char *file) +{ + size_t n; + + if (file == NULL || file[0] == '\n') + return "RAW"; + + n = strlen(file); + if (n > 4 && strcasecmp(file + (n - 4), ".vdi") == 0) + return "VDI"; + if (n > 4 && strcasecmp(file + (n - 4), ".vhd") == 0) + return "VHD"; + if (n > 5 && strcasecmp(file + (n - 5), ".vmdk") == 0) + return "VMDK"; + + if (n > 5 && strcasecmp(file + (n - 5), ".qcow") == 0) + return "QCOW"; + if (n > 6 && strcasecmp(file + (n - 6), ".qcow2") == 0) + return "QCOW"; + if (n > 4 && strcasecmp(file + (n - 4), ".qed") == 0) + return "QED"; + if (n > 5 && strcasecmp(file + (n - 5), ".vhdx") == 0) + return "VHDX"; + + return "RAW"; +} + +int +istgt_lu_disk_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + uint64_t gb_size; + uint64_t mb_size; +#ifdef HAVE_UUID_H + uint32_t status; +#endif /* HAVE_UUID_H */ + int flags, rpm; + int rc; + int i, j, k; + uint32_t lbPerRecord = 0; + + printf("LU%d HDD UNIT\n", lu->num); + ISTGT_NOTICELOG("lu_disk_init LU%d TargetName=%s", + lu->num, lu->name); + + for (i = 0; i < lu->maxlun; i++) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); + lu->lun[i].spec = NULL; + continue; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d storage\n", + lu->num, i); + + spec = xmalloc(sizeof *spec); + memset(spec, 0, sizeof *spec); + spec->lu = lu; + spec->num = lu->num; + spec->lun = i; + spec->do_avg = 0; + spec->inflight = 0; + spec->fd = -1; + spec->ludsk_ref = 0; + spec->max_unmap_sectors = 4096; + spec->persist = is_persist_enabled(); + spec->luworkers = lu->luworkers; + spec->luworkersActive = lu->luworkersActive; + + spec->readcache = spec->lu->lun[i].readcache; + spec->writecache = spec->lu->lun[i].writecache; + spec->unmap = spec->lu->lun[i].unmap; + spec->wzero = spec->lu->lun[i].wzero; + spec->ats = spec->lu->lun[i].ats; + spec->xcopy = spec->lu->lun[i].xcopy; + spec->wsame = spec->lu->lun[i].wsame; + spec->dpofua = spec->lu->lun[i].dpofua; + rpm = spec->lu->lun[i].rotationrate; + + spec->watsbuf = NULL; + + spec->queue_depth = lu->queue_depth; + + spec->disk_modify_work_pending = 0; + + rc = pthread_cond_init(&spec->cmd_queue_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: cond_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + istgt_queue_init(&spec->cmd_queue); + + rc = pthread_cond_init(&spec->maint_cmd_queue_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: maint_cond_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + istgt_queue_init(&spec->maint_cmd_queue); + istgt_queue_init(&spec->maint_blocked_queue); + + rc = pthread_mutex_init(&spec->clone_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: clone_mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + rc = pthread_mutex_init(&spec->complete_queue_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: comp_q_mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + istgt_queue_init(&spec->complete_queue); + + rc = pthread_mutex_init(&spec->wait_lu_task_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: wait_mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + rc = pthread_mutex_init(&spec->schdler_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: scheduler mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + rc = pthread_mutex_init(&spec->sleep_mutex, &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: sleep mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + rc = pthread_cond_init(&spec->schdler_cond, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d:scheduler cond_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + for(k = 0; k < ISTGT_MAX_NUM_LUWORKERS; k++) { + spec->inflight_io[k] = NULL; + spec->wait_lu_task[k] = NULL; + spec->lu_tmf_wait[k] = 0; + + rc = pthread_mutex_init(&spec->luworker_mutex[k], &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: luworker %d mutex_init() failed errno:%d\n", lu->num, k, errno); + return -1; + } + + rc = pthread_cond_init(&spec->luworker_cond[k], NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: luworker %d cond_init() failed errno:%d\n", lu->num, k, errno); + return -1; + } + + rc = pthread_mutex_init(&spec->lu_tmf_mutex[k], &istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: lu_tmf_mutex %d mutex_init() failed errno:%d\n", lu->num, k, errno); + return -1; + } + + rc = pthread_cond_init(&spec->lu_tmf_cond[k], NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: lu_tmf_cond %d cond_init() failed errno:%d\n", lu->num, k, errno); + return -1; + } + } + istgt_queue_init(&spec->blocked_queue); + + memset(&spec->lu_free_matrix, 0, ((ISTGT_MAX_NUM_LUWORKERS/32)+1)*4); + memset(&spec->luworker_waiting, 0, sizeof(spec->luworker_waiting)); + spec->schdler_waiting = 0; + spec->schdler_cmd_waiting = 0; + spec->error_count = 0; + spec->maint_thread_waiting = 0; + + rc = pthread_mutex_init(&spec->pr_rsv_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: persistent reservation mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + rc = pthread_mutex_init(&spec->state_mutex, NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_init() failed errno:%d\n", lu->num, errno); + return -1; + } + + spec->npr_keys = 0; + for (j = 0; j < MAX_LU_RESERVE; j++) { + spec->pr_keys[j].registered_initiator_port = NULL; + } + spec->pr_generation = 0; + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + spec->rsv_pending = ISTGT_RSV_NONE; + + TAILQ_INIT(&spec->nexus); + +#ifdef HAVE_UUID_H + uuid_create(&spec->uuid, &status); + if (status != uuid_s_ok) { + ISTGT_ERRLOG("LU%d: LUN%d: uuid_create() failed\n", lu->num, i); + (void) pthread_mutex_destroy(&spec->wait_lu_task_mutex); + (void) pthread_mutex_destroy(&spec->complete_queue_mutex); + (void) pthread_mutex_destroy(&spec->pr_rsv_mutex); + (void) pthread_mutex_destroy(&spec->state_mutex); + (void) pthread_mutex_destroy(&spec->schdler_mutex); + (void) pthread_mutex_destroy(&spec->sleep_mutex); + (void) pthread_cond_destroy(&spec->schdler_cond); + (void) pthread_cond_destroy(&spec->cmd_queue_cond); + (void) pthread_cond_destroy(&spec->maint_cmd_queue_cond); + istgt_queue_destroy(&spec->cmd_queue); + istgt_queue_destroy(&spec->blocked_queue); + istgt_queue_destroy(&spec->maint_cmd_queue); + istgt_queue_destroy(&spec->maint_blocked_queue); + for(k = 0; k < ISTGT_MAX_NUM_LUWORKERS; k++) { + (void) pthread_mutex_destroy(&spec->luworker_mutex[k]); + (void) pthread_cond_destroy(&spec->luworker_cond[k]); + } + xfree(spec); + return -1; + } +#endif /* HAVE_UUID_H */ + + spec->file = lu->lun[i].u.storage.file; + spec->size = lu->lun[i].u.storage.size; + spec->rsize = lu->lun[i].u.storage.rsize; + spec->disktype = istgt_get_disktype_by_ext(spec->file); + if (strcasecmp(spec->disktype, "VDI") == 0 + || strcasecmp(spec->disktype, "VHD") == 0 + || strcasecmp(spec->disktype, "VMDK") == 0 + || strcasecmp(spec->disktype, "QCOW") == 0 + || strcasecmp(spec->disktype, "QED") == 0 + || strcasecmp(spec->disktype, "VHDX") == 0) { + rc = istgt_lu_disk_vbox_lun_init(spec, istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_vbox_lun_init() failed\n", + lu->num, i); + goto error_return; + } + } else if (strcasecmp(spec->disktype, "RAW") == 0) { + spec->open = istgt_lu_disk_open_raw; + spec->close = istgt_lu_disk_close_raw; + spec->seek = istgt_lu_disk_seek_raw; + spec->sync = istgt_lu_disk_sync_raw; + spec->allocate = istgt_lu_disk_allocate_raw; + spec->setcache = istgt_lu_disk_setcache_raw; + + spec->rshift = lu->rshift; + spec->blocklen = lu->blocklen; + if (spec->blocklen != 512 + && spec->blocklen != 1024 + && spec->blocklen != 2048 + && spec->blocklen != 4096 + && spec->blocklen != 8192 + && spec->blocklen != 16384 + && spec->blocklen != 32768 + && spec->blocklen != 65536 + && spec->blocklen != 131072 + && spec->blocklen != 262144 + && spec->blocklen != 524288) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen %"PRIu64"\n", + lu->num, i, spec->blocklen); + error_return: + (void) pthread_mutex_destroy(&spec->wait_lu_task_mutex); + (void) pthread_mutex_destroy(&spec->complete_queue_mutex); + (void) pthread_mutex_destroy(&spec->pr_rsv_mutex); + (void) pthread_mutex_destroy(&spec->state_mutex); + (void) pthread_mutex_destroy(&spec->schdler_mutex); + (void) pthread_mutex_destroy(&spec->sleep_mutex); + (void) pthread_cond_destroy(&spec->schdler_cond); + (void) pthread_cond_destroy(&spec->cmd_queue_cond); + (void) pthread_cond_destroy(&spec->maint_cmd_queue_cond); + istgt_queue_destroy(&spec->cmd_queue); + istgt_queue_destroy(&spec->blocked_queue); + istgt_queue_destroy(&spec->maint_cmd_queue); + istgt_queue_destroy(&spec->maint_blocked_queue); + for(k = 0; k < ISTGT_MAX_NUM_LUWORKERS; k++) { + (void) pthread_mutex_destroy(&spec->luworker_mutex[k]); + (void) pthread_cond_destroy(&spec->luworker_cond[k]); + } + xfree(spec); + return -1; + } + spec->blockcnt = spec->size / spec->blocklen; + if (spec->blockcnt == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: size zero\n", lu->num, i); + goto error_return; + } + spec->lb_per_rec = 1; + spec->rshiftreal = 0; + if (spec->rsize > spec->blocklen) { + lbPerRecord = spec->rsize / ((uint32_t)(spec->blocklen)); + spec->lb_per_rec = lbPerRecord; + spec->rshiftreal = fls(lbPerRecord) - 1; + if (lbPerRecord & (lbPerRecord-1)) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen:%lu zfsrecordSize:%u\n", + lu->num, i, spec->blocklen, spec->rsize); + } + } +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "LU%d: LUN%d file=%s, size=%"PRIu64"\n", + lu->num, i, spec->file, spec->size); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "LU%d: LUN%d %"PRIu64" blocks, %" + PRIu64" bytes/block\n", + lu->num, i, spec->blockcnt, spec->blocklen); +#endif + + if (lu->istgt->OperationalMode) { + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + spec->ex_state = ISTGT_LUN_NOTYET; + MTX_UNLOCK(&spec->state_mutex); + + gb_size = spec->size / ISTGT_LU_1GB; + mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB; + printf("LU%d: LUN%d %s: storage_offline %s [%s, size=%"PRIu64"GB %"PRIu64"MB %"PRIu64" blocks, %"PRIu64" bytes/block %u]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rsize); + ISTGT_LOG("LU%d: LUN%d %s: storage_offline %s [%s, size=%"PRIu64"GB %"PRIu64"MB %"PRIu64" blocks, %"PRIu64" bytes/block %u]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rsize); + } else { + struct timespec _s1, _s2, _wrk, _wrkx; + flags = lu->readonly ? O_RDONLY : O_RDWR; + clock_gettime(clockid, &_wrk); + rc = spec->open(spec, flags, 0666); + timesdiff(_wrk, _wrkx, _s1) + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d/%d)[%s]\n", + lu->num, i, spec->fderr, spec->fderrno, spec->file); + flags = lu->readonly ? O_RDONLY : (O_CREAT | O_EXCL | O_RDWR); + rc = spec->open(spec, flags, 0666); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d/%d)[%s]\n", + lu->num, i, spec->fderr, spec->fderrno, spec->file); + goto error_return; + } + } + if (!lu->readonly) { + rc = spec->allocate(spec); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n", + lu->num, i); + rc = spec->close(spec); + if(rc < 0 ) { + ISTGT_ERRLOG("LU%d:LUN%d: close error\n", lu->num, i); + /* Ignore error */ + } + goto error_return; + } + } + /* + if (spec->rsize == 0) { + off_t rsize = 0; + rc = ioctl(spec->fd, DIOCGSTRIPESIZE, &rsize); + if (rc != -1) { + ISTGT_ERRLOG("LU%d: LUN%d: ioctl-blksize:%lu\n", lu->num, i, rsize); + spec->rsize = rsize; + if (spec->rsize > spec->blocklen) { + lbPerRecord = spec->rsize / ((uint32_t)(spec->blocklen)); + spec->lb_per_rec = lbPerRecord; + spec->rshiftreal = fls(lbPerRecord) - 1; + if (lbPerRecord & (lbPerRecord-1)) { + ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen:%lu zfsrecordSize:%u\n", + lu->num, i, spec->blocklen, spec->rsize); + } + } + } else { + ISTGT_ERRLOG("LU%d: LUN%d: ioctl-blksize:%lu failed:%d %d\n", lu->num, i, rsize, rc, errno); + } + } + */ + rc = spec->setcache(spec); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: setcache error\n", lu->num, i); + rc = spec->close(spec); + if(rc < 0 ) { + ISTGT_ERRLOG("LU%d:LUN%d: close error\n", lu->num, i); + /* Ignore error */ + } + goto error_return; + } + if(spec->persist){ + ISTGT_LOG("READING RESERVATION FROM ZAP"); + MTX_LOCK(&spec->pr_rsv_mutex); + spec->rsv_pending |= ISTGT_RSV_READ; + //rc = istgt_lu_disk_get_reservation(spec); + MTX_UNLOCK(&spec->pr_rsv_mutex); + spec->state = ISTGT_LUN_BUSY; + spec->ex_state = ISTGT_LUN_OPEN; + //if (rc < 0) { + // ISTGT_ERRLOG("istgt_lu_disk_get_reservation() failed\n"); + //} + } else { + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_ONLINE; + spec->ex_state = ISTGT_LUN_OPEN; + MTX_UNLOCK(&spec->state_mutex); + } + timesdiff(_wrkx, _wrk, _s2) + + gb_size = spec->size / ISTGT_LU_1GB; + mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB; + printf("LU%d: LUN%d %s: storage_online %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u/%u %s%s%s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d [%ld.%ld, %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, spec->rshiftreal, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "", spec->xcopy ? " XCOPY" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + spec->wzero ? " WZERO" : "", + rpm, spec->queue_depth, spec->luworkers, spec->luworkersActive, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec); + ISTGT_LOG("LU%d: LUN%d %s: storage_online %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u/%u %s%s%s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d [%ld.%ld, %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, spec->rshiftreal, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "",spec->xcopy ? " XCOPY" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + spec->wzero ? " WZERO" : "", + rpm, spec->queue_depth, spec->luworkers, spec->luworkersActive, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec); + } + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unsupported format\n", lu->num, i); + goto error_return; + } + + printf("LU%d: LUN%d serial:%s\n", lu->num, i, + spec->lu->lun[i].serial != NULL ? spec->lu->lun[i].serial : spec->lu->inq_serial); + ISTGT_LOG("LU%d: LUN%d serial:%s\n", lu->num, i, + spec->lu->lun[i].serial != NULL ? spec->lu->lun[i].serial : spec->lu->inq_serial); + + + /* Needs a thot */ + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + nexus->ua_pending |= ISTGT_UA_RES_PREEMPT; + } + + lu->lun[i].spec = spec; + } + + return 0; +} + +int +istgt_lu_disk_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + ISTGT_LU_PR_KEY *prkey; + int rc; + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s istgt_lu_disk_shutdown\n", + lu->num, lu->name); + for (i = 0; i < lu->maxlun; i++) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); + continue; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[i].spec; + + /* CloudByte: Spec can be null when there is a LUN initialization failure. */ + if (spec == NULL) + continue; + + if (strcasecmp(spec->disktype, "VDI") == 0 + || strcasecmp(spec->disktype, "VHD") == 0 + || strcasecmp(spec->disktype, "VMDK") == 0 + || strcasecmp(spec->disktype, "QCOW") == 0 + || strcasecmp(spec->disktype, "QED") == 0 + || strcasecmp(spec->disktype, "VHDX") == 0) { + rc = istgt_lu_disk_vbox_lun_shutdown(spec, istgt, lu); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: lu_disk_vbox_lun_shutdown() failed\n", + lu->num); + /* ignore error */ + } + } else if (strcasecmp(spec->disktype, "RAW") == 0) { + int workers_signaled = 0, loop = 0; + struct timespec _s1, _s2, _s3, _wrk, _wrkx; + + clock_gettime(clockid, &_wrk); + do { + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + if (spec->ludsk_ref == 0) + workers_signaled = 1; + spec->ex_state = ISTGT_LUN_CLOSE_INPROGRESS; + MTX_UNLOCK(&spec->state_mutex); + if (workers_signaled == 0) + sleep(1); + } while ((workers_signaled == 0) && (++loop < 10)); + + timesdiff(_wrk, _wrkx, _s1) + if (!spec->lu->readonly) { + rc = spec->sync(spec, 0, spec->size); + if (rc < 0) { + //ISTGT_ERRLOG("LU%d: lu_disk_sync() failed\n", lu->num); + /* ignore error */ + } + } + timesdiff(_wrkx, _wrk, _s2) + rc = spec->close(spec); + if (rc < 0) { + //ISTGT_ERRLOG("LU%d: lu_disk_close() failed\n", lu->num); + /* ignore error */ + } + MTX_LOCK(&spec->state_mutex); + spec->ex_state = ISTGT_LUN_CLOSE; + MTX_UNLOCK(&spec->state_mutex); + timesdiff(_wrk, _wrkx, _s3) + ISTGT_LOG("LU%d: LUN%d %s: storage_offlinex %s [%s %"PRIu64" blocks, %"PRIu64" bytes/block] [%ld.%ld %ld.%ld %ld.%ld]\n", + lu->num, i, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, spec->blockcnt, spec->blocklen, + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec, _s3.tv_sec, _s3.tv_nsec); + } else { + ISTGT_ERRLOG("LU%d: LUN%d: unsupported format\n", lu->num, i); + return -1; + } + + for (j = 0; j < spec->npr_keys; j++) { + prkey = &spec->pr_keys[j]; + istgt_lu_disk_free_pr_key(prkey); + } + if (spec->rsv_key != 0) { + xfree(spec->rsv_port); + spec->rsv_port = NULL; + } + + lu->limit_q_size = 0; + + if (lu->queue_depth != 0) { + for ( i=0; i < lu->luworkers; i++ ) { + MTX_LOCK(&spec->luworker_mutex[i]); + rc = pthread_cond_broadcast(&spec->luworker_cond[i]); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: %d luthread cond_broadcast() failed:%d\n", lu->num, i, rc); + } + MTX_UNLOCK(&spec->luworker_mutex[i]); + } + + MTX_LOCK(&spec->schdler_mutex); + rc = pthread_cond_broadcast(&spec->schdler_cond); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: schdler_cond_broadcast() failed:%d\n", lu->num, rc); + } + MTX_UNLOCK(&spec->schdler_mutex); + + MTX_LOCK(&spec->complete_queue_mutex); + rc = pthread_cond_broadcast(&spec->cmd_queue_cond); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: cmd_q cond_broadcast() failed:%d\n", lu->num, rc); + } + + rc = pthread_cond_broadcast(&spec->maint_cmd_queue_cond); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: maint_q cond_broadcast() failed:%d\n", lu->num, rc); + } + MTX_UNLOCK(&spec->complete_queue_mutex); + + for ( i=0; i < lu->luworkers; i++ ) { + if (lu->luthread[i] == 0) + continue; + rc = pthread_join(lu->luthread[i], NULL); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: pthread_join() failed for thread join op %d\n", lu->num, i); + } else { + --lu->luworkersActive; + } + } + rc = pthread_join(lu->schdler_thread, NULL); + if (rc != 0) + ISTGT_ERRLOG("LU%d: pthread_join() failed for schdler thread join\n", lu->num); + rc = pthread_join(lu->maintenance_thread, NULL); + if (rc != 0) + ISTGT_ERRLOG("LU%d: pthread_join() failed for maint thread join\n", lu->num); + } + istgt_queue_destroy(&spec->cmd_queue); + istgt_queue_destroy(&spec->maint_cmd_queue); + istgt_queue_destroy(&spec->maint_blocked_queue); + rc = pthread_mutex_destroy(&spec->complete_queue_mutex); + rc = pthread_cond_destroy(&spec->maint_cmd_queue_cond); + + rc = pthread_mutex_destroy(&spec->schdler_mutex); + rc = pthread_mutex_destroy(&spec->sleep_mutex); + rc = pthread_cond_destroy(&spec->schdler_cond); + rc = pthread_cond_destroy(&spec->cmd_queue_cond); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + istgt_queue_destroy(&spec->blocked_queue); + + for ( i=0; i < lu->luworkers; i++ ) { + rc = pthread_mutex_destroy(&spec->luworker_mutex[i]); + rc = pthread_cond_destroy(&spec->luworker_cond[i]); + } + rc = pthread_mutex_destroy(&spec->wait_lu_task_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&spec->clone_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: clone_mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&spec->pr_rsv_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num); + /* ignore error */ + } + rc = pthread_mutex_destroy(&spec->state_mutex); + if (rc != 0){ + /* ignore error */ + } + xfree(spec->watsbuf); + while ((nexus = TAILQ_FIRST(&spec->nexus))) { + TAILQ_REMOVE(&spec->nexus, nexus, nexus_next); + xfree(nexus); + } + xfree(spec); + lu->lun[i].spec = NULL; + } + + return 0; +} + +void +istgt_scsi_dump_cdb(uint8_t *cdb) +{ + int group; + int cdblen = 0; + int i; + + if (cdb == NULL) + return; + + group = (cdb[0] >> 5) & 0x07; + switch (group) { + case 0x00: + /* 6byte commands */ + cdblen = 6; + break; + case 0x01: + /* 10byte commands */ + cdblen = 10; + break; + case 0x02: + /* 10byte commands */ + cdblen = 10; + break; + case 0x03: + /* reserved */ + if (cdb[0] == 0x7f) { + /* variable length */ + cdblen = 8 + (cdb[7] & 0xff); + } else { + /* XXX */ + cdblen = 6; + } + break; + case 0x04: + /* 16byte commands */ + cdblen = 16; + break; + case 0x05: + /* 12byte commands */ + cdblen = 12; + break; + case 0x06: + case 0x07: + /* vendor specific */ + cdblen = 6; + break; + } + + printf("CDB="); + for (i = 0; i < cdblen; i++) { + printf("%2.2x ", cdb[i]); + } + printf("\n"); +} + +void +istgt_strcpy_pad(uint8_t *dst, size_t size, const char *src, int pad) +{ + size_t len; + + len = strlen(src); + if (len < size) { + memcpy(dst, src, len); + memset(dst + len, pad, (size - len)); + } else { + memcpy(dst, src, size); + } +} + +#ifdef HAVE_UUID_H +uint64_t +istgt_uuid2uint64(uuid_t *uuid) +{ + uint64_t low, mid, hi; + uint64_t r; + + low = (uint64_t) uuid->time_low; + mid = (uint64_t) uuid->time_mid; + hi = (uint64_t) uuid->time_hi_and_version; + r = (hi & 0xffffULL) << 48; + r |= (mid & 0xffffULL) << 32; + r |= (low & 0xffffffffULL); + return r; +} +#endif /* HAVE_UUID_H */ + +uint64_t +istgt_get_lui(const char *name, int lun) +{ + char buf[MAX_TMPBUF]; + uint32_t crc32c; + uint64_t r; + + if (lun >= 0) { + snprintf(buf, sizeof buf, "%s,%d", + name, lun); + } else { + snprintf(buf, sizeof buf, "%s", + name); + } + crc32c = istgt_crc32c((uint8_t *) buf, strlen(buf)); + r = (uint64_t) crc32c; + return r; +} + +uint64_t +istgt_get_rkey(const char *initiator_name, uint64_t lui) +{ + ISTGT_MD5CTX md5ctx; + uint8_t rkeymd5[ISTGT_MD5DIGEST_LEN]; + char buf[MAX_TMPBUF]; + uint64_t rkey; + int idx; + int i; + + snprintf(buf, sizeof buf, "%s,%16.16" PRIx64, + initiator_name, lui); + + istgt_md5init(&md5ctx); + istgt_md5update(&md5ctx, buf, strlen(buf)); + istgt_md5final(rkeymd5, &md5ctx); + + rkey = 0U; + idx = ISTGT_MD5DIGEST_LEN - 8; + if (idx < 0) { + ISTGT_WARNLOG("missing MD5 length\n"); + idx = 0; + } + for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) { + rkey |= (uint64_t) rkeymd5[i]; + rkey = rkey << 8; + } + return rkey; +} + +/* XXX */ +#define COMPANY_ID 0xACDE48U // 24bits + +int +istgt_lu_set_lid(uint8_t *buf, uint64_t vid) +{ + uint64_t naa; + uint64_t enc; + int total; + + naa = 0x3; // Locally Assigned + + /* NAA + LOCALLY ADMINISTERED VALUE */ + enc = (naa & 0xfULL) << (64-4); // 4bits + enc |= vid & 0xfffffffffffffffULL; //60bits + DSET64(&buf[0], enc); + + total = 8; + return total; +} + +int +istgt_lu_set_id(uint8_t *buf, uint64_t vid) +{ + uint64_t naa; + uint64_t cid; + uint64_t enc; + int total; + + naa = 0x5; // IEEE Registered + cid = COMPANY_ID; //IEEE COMPANY_ID + + /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */ + enc = (naa & 0xfULL) << (64-4); // 4bits + enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits + enc |= vid & 0xfffffffffULL; //36bits + DSET64(&buf[0], enc); + + total = 8; + return total; +} + +int +istgt_lu_set_extid(uint8_t *buf, uint64_t vid, uint64_t vide) +{ + uint64_t naa; + uint64_t cid; + uint64_t enc; + int total; + + naa = 0x6; // IEEE Registered Extended + cid = COMPANY_ID; //IEEE COMPANY_ID + + /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */ + enc = (naa & 0xfULL) << (64-4); // 4bits + enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits + enc |= vid & 0xfffffffffULL; //36bits + DSET64(&buf[0], enc); + /* VENDOR SPECIFIC IDENTIFIER EXTENSION */ + DSET64(&buf[8], vide); + + total = 16; + return total; +} + +static int +istgt_lu_disk_scsi_report_luns(ISTGT_LU_Ptr lu, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int sel, uint8_t *data, int alloc_len) +{ + uint64_t fmt_lun, lun, method; + int hlen = 0, len = 0; + int i; + + if (alloc_len < 8) { + return -1; + } + + if (sel == 0x00) { + /* logical unit with addressing method */ + } else if (sel == 0x01) { + /* well known logical unit */ + } else if (sel == 0x02) { + /* logical unit */ + } else { + return -1; + } + + /* LUN LIST LENGTH */ + DSET32(&data[0], 0); + /* Reserved */ + DSET32(&data[4], 0); + hlen = 8; + + for (i = 0; i < lu->maxlun; i++) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); +#endif + continue; + } + if (alloc_len - (hlen + len) < 8) { + return -1; + } + lun = (uint64_t) i; + if (lu->maxlun <= 0x0100) { + /* below 256 */ + method = 0x00U; + fmt_lun = (method & 0x03U) << 62; + fmt_lun |= (lun & 0x00ffU) << 48; + } else if (lu->maxlun <= 0x4000) { + /* below 16384 */ + method = 0x01U; + fmt_lun = (method & 0x03U) << 62; + fmt_lun |= (lun & 0x3fffU) << 48; + } else { + /* XXX */ + fmt_lun = 0; + } + /* LUN */ + DSET64(&data[hlen + len], fmt_lun); + len += 8; + } + /* LUN LIST LENGTH */ + DSET32(&data[0], len); + return hlen + len; +} + +//extern int enable_xcopy; +extern int enable_oldBL; + +static int +istgt_lu_disk_scsi_inquiry(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len) +{ + uint64_t LUI; + uint8_t *cp, *cp2; + uint32_t blocks; + int hlen = 0, len = 0, plen, plen2; + int pc; + int pq, pd; + int rmb; + int evpd; + int pg_tag; + int i, j; + uint64_t *tptr; + if (alloc_len < 0xff) { + return -1; + } + + pq = 0x00; + pd = SPC_PERIPHERAL_DEVICE_TYPE_DISK; + rmb = 0; + +#if 0 + LUI = istgt_uuid2uint64(&spec->uuid); +#else + LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU); +#endif + + pc = cdb[2]; + evpd = BGET8(&cdb[1], 0); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d INQUIRY\n", conn->id); + if (evpd) { + /* Vital product data */ + switch (pc) { + case SPC_VPD_SUPPORTED_VPD_PAGES: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* Reserved */ + data[2] = 0; + /* PAGE LENGTH */ + data[3] = 0; + hlen = 4; + + data[4] = SPC_VPD_SUPPORTED_VPD_PAGES; /* 0x00 */ + data[5] = SPC_VPD_UNIT_SERIAL_NUMBER; /* 0x80 */ + data[6] = SPC_VPD_DEVICE_IDENTIFICATION; /* 0x83 */ + data[7] = SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES; /* 0x85 */ + data[8] = SPC_VPD_EXTENDED_INQUIRY_DATA; /* 0x86 */ + data[9] = SPC_VPD_MODE_PAGE_POLICY; /* 0x87 */ + data[10]= SPC_VPD_SCSI_PORTS; /* 0x88 */ + data[11]= 0xb0; /* SBC Block Limits */ + data[12]= 0xb1; /* SBC Block Device Characteristics */ + len = 13 - hlen; + if (spec->unmap) { + data[13]= 0xb2; /* SBC Thin Provisioning */ + len++; + } + + /* PAGE LENGTH */ + data[3] = len; + break; + + case SPC_VPD_UNIT_SERIAL_NUMBER: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* Reserved */ + data[2] = 0; + /* PAGE LENGTH */ + data[3] = 0; + hlen = 4; + + /* PRODUCT SERIAL NUMBER */ + if (spec->lu->lun[spec->lun].serial != NULL) { + len = strlen(spec->lu->lun[spec->lun].serial); + if (len > MAX_LU_SERIAL_STRING) { + len = MAX_LU_SERIAL_STRING; + } + istgt_strcpy_pad(&data[4], len, + spec->lu->lun[spec->lun].serial, ' '); + } else { + len = strlen(spec->lu->inq_serial); + if (len > MAX_LU_SERIAL_STRING) { + len = MAX_LU_SERIAL_STRING; + } + istgt_strcpy_pad(&data[4], len, + spec->lu->inq_serial, ' '); + } + + /* PAGE LENGTH */ + data[3] = len; + break; + + case SPC_VPD_DEVICE_IDENTIFICATION: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* Identification descriptor 1 */ + /* Logical Unit */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], 0, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + DSET8(&data[3], 8); + //cp[3] = 0; + + /* IDENTIFIER */ +#if 0 + /* 16bytes ID */ + plen = istgt_lu_set_extid(&cp[4], 0, LUI); +#else + plen = istgt_lu_set_lid(&cp[4], LUI); + + + cp[3] = plen; + len += 4 + plen; +#endif + /* Identification descriptor 2 */ + /* T10 VENDOR IDENTIFICATION */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], 0, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + /* T10 VENDOR IDENTIFICATION */ + istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' '); + plen = 8; + /* VENDOR SPECIFIC IDENTIFIER */ + /* PRODUCT IDENTIFICATION */ + istgt_strcpy_pad(&cp[12], 16, spec->lu->inq_product, ' '); + /* PRODUCT SERIAL NUMBER */ + if (spec->lu->lun[spec->lun].serial != NULL) { + istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING, + spec->lu->lun[spec->lun].serial, ' '); + } else { + istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING, + spec->lu->inq_serial, ' '); + } + plen += 16 + MAX_LU_SERIAL_STRING; + + cp[3] = plen; + len += 4 + plen; + + /* Identification descriptor 3 */ + /* Target Device */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_DEVICE, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + plen = snprintf((char *) &cp[4], MAX_TARGET_NAME, + "%s", spec->lu->name); + cp[3] = plen; + len += 4 + plen; + + /* Identification descriptor 4 */ + /* Target Port */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + plen = snprintf((char *) &cp[4], MAX_TARGET_NAME, + "%s"",t,0x""%4.4x", spec->lu->name, conn->portal.tag); + cp[3] = plen; + len += 4 + plen; + + /* Identification descriptor 5 */ + /* Relative Target Port */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT, + 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + /* Obsolete */ + DSET16(&cp[4], 0); + /* Relative Target Port Identifier */ + //DSET16(&cp[6], 1); /* port1 as port A */ + //DSET16(&cp[6], 2); /* port2 as port B */ + DSET16(&cp[6], (uint16_t) (1 + conn->portal.idx)); + plen = 4; + + cp[3] = plen; + len += 4 + plen; + + /* Identification descriptor 6 */ + /* Target port group */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP, + 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + /* Reserved */ + DSET16(&cp[4], 0); + /* TARGET PORT GROUP */ + DSET16(&cp[6], (uint16_t) (conn->portal.tag)); + plen = 4; + + cp[3] = plen; + len += 4 + plen; + + /* Identification descriptor 7 */ + /* Logical unit group */ + cp = &data[hlen + len]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2); + BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP, + 3, 4); + /* Reserved */ + cp[2] = 0; + /* IDENTIFIER LENGTH */ + cp[3] = 0; + + /* IDENTIFIER */ + /* Reserved */ + DSET16(&cp[4], 0); + /* LOGICAL UNIT GROUP */ + DSET16(&cp[6], (uint16_t) (spec->lu->num)); + plen = 4; + + cp[3] = plen; + len += 4 + plen; + + /* PAGE LENGTH */ + if (len > 0xffff) { + len = 0xffff; + } + DSET16(&data[2], len); + break; + + case SPC_VPD_EXTENDED_INQUIRY_DATA: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* Reserved */ + data[2] = 0; + /* PAGE LENGTH */ + data[3] = 0; + hlen = 4; + + /* RTO(3) GRD_CHK(2) APP_CHK(1) REF_CHK(0) */ + data[4] = 0; + /* GROUP_SUP(4) PRIOR_SUP(3) HEADSUP(2) ORDSUP(1) SIMPSUP(0) */ + data[5] = 0; + if (spec->queue_depth != 0) { + BDADD8(&data[5], 1, 2); /* HEADSUP */ + //BDADD8(&data[5], 1, 1); /* ORDSUP */ + BDADD8(&data[5], 1, 0); /* SIMPSUP */ + } + /* NV_SUP(1) V_SUP(0) */ + data[6] = 0; + /* Reserved[7-63] */ + //memset(&data[7], 0, (64 - 7)); + data[7] = 0; + tptr = (uint64_t *)&(data[8]); + *tptr = 0; *(tptr+1) = 0; *(tptr+2) = 0; *(tptr+3) = 0; + *(tptr+4) = 0; *(tptr+5) = 0; *(tptr+6) = 0; + + len = 64 - hlen; + + /* PAGE LENGTH */ + data[3] = len; + break; + + case SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + +#if 0 + /* Network services descriptor N */ + cp = &data[hlen + len]; + + /* ASSOCIATION(6-5) SERVICE TYPE(4-0) */ + BDSET8W(&cp[0], 0x00, 6, 2); + BDADD8W(&cp[0], 0x00, 4, 5); + /* Reserved */ + cp[1] = 0; + /* NETWORK ADDRESS LENGTH */ + DSET16(&cp[2], 0); + /* NETWORK ADDRESS */ + cp[4] = 0; + /* ... */ + plen = 0; + DSET16(&cp[2], plen); + len += 4 + plen; +#endif + + /* PAGE LENGTH */ + if (len > 0xffff) { + len = 0xffff; + } + DSET16(&data[2], len); + break; + + case SPC_VPD_MODE_PAGE_POLICY: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* Mode page policy descriptor 1 */ + cp = &data[hlen + len]; + + /* POLICY PAGE CODE(5-0) */ + BDSET8W(&cp[0], 0x3f, 5, 6); /* all page code */ + /* POLICY SUBPAGE CODE */ + cp[1] = 0xff; /* all sub page */ + /* MLUS(7) MODE PAGE POLICY(1-0) */ + //BDSET8(&cp[2], 1, 7); /* multiple logical units share */ + BDSET8(&cp[2], 0, 7); /* own copy */ + BDADD8W(&cp[2], 0x00, 1, 2); /* Shared */ + //BDADD8W(&cp[2], 0x01, 1, 2); /* Per target port */ + //BDADD8W(&cp[2], 0x02, 1, 2); /* Per initiator port */ + //BDADD8W(&cp[2], 0x03, 1, 2); /* Per I_T nexus */ + /* Reserved */ + cp[3] = 0; + len += 4; + + /* PAGE LENGTH */ + if (len > 0xffff) { + len = 0xffff; + } + DSET16(&data[2], len); + break; + + case SPC_VPD_SCSI_PORTS: + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* Identification descriptor list */ + for (i = 0; i < spec->lu->maxmap; i++) { + pg_tag = spec->lu->map[i].pg_tag; + /* skip same pg_tag */ + for (j = 0; j < i; j++) { + if (spec->lu->map[j].pg_tag == pg_tag) { + goto skip_pg_tag; + } + } + + /* Identification descriptor N */ + cp = &data[hlen + len]; + + /* Reserved */ + DSET16(&cp[0], 0); + /* RELATIVE PORT IDENTIFIER */ + DSET16(&cp[2], (uint16_t) (1 + pg_tag)); + /* Reserved */ + DSET16(&cp[4], 0); + /* INITIATOR PORT TRANSPORTID LENGTH */ + DSET16(&cp[6], 0); + /* Reserved */ + DSET16(&cp[8], 0); + /* TARGET PORT DESCRIPTORS LENGTH */ + DSET16(&cp[10], 0); + len += 12; + + plen2 = 0; + /* Target port descriptor 1 */ + cp2 = &data[hlen + len + plen2]; + + /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */ + BDSET8W(&cp2[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4); + BDADD8W(&cp2[0], SPC_VPD_CODE_SET_UTF8, 3, 4); + /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */ + BDSET8W(&cp2[1], 1, 7, 1); /* PIV */ + BDADD8W(&cp2[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2); + BDADD8W(&cp2[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4); + /* Reserved */ + cp2[2] = 0; + /* IDENTIFIER LENGTH */ + cp2[3] = 0; + + /* IDENTIFIER */ + plen = snprintf((char *) &cp2[4], MAX_TARGET_NAME, + "%s"",t,0x""%4.4x", spec->lu->name, pg_tag); + cp2[3] = plen; + plen2 += 4 + plen; + + /* TARGET PORT DESCRIPTORS LENGTH */ + DSET16(&cp[10], plen2); + len += plen2; + skip_pg_tag: + ; + } + + /* PAGE LENGTH */ + if (len > 0xffff) { + len = 0xffff; + } + DSET16(&data[2], len); + break; + + case 0xb0: /* SBC Block Limits */ + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* WSNZ(0) */ + BDSET8(&data[4], 0, 0); /* support zero length in WRITE SAME */ + + /* MAXIMUM COMPARE AND WRITE LENGTH */ + if (spec->lu->lun[0].ats) { + blocks = ISTGT_LU_WORK_ATS_BLOCK_SIZE / (uint32_t) spec->blocklen; + if (blocks > 0xff) + blocks = 0xff; + data[5] = (uint8_t) blocks; + } + if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) { + /* no support compare and write */ + data[5] = 0; + } + + if (enable_oldBL == 1) { + /* force align to 4KB */ + if (spec->blocklen < 4096) + blocks = 4096 / (uint32_t) spec->blocklen; + else + blocks = 1; + } else { + blocks = spec->lb_per_rec; + if (blocks == 0) //this would not happen + blocks = 1; + } + /* OPTIMAL TRANSFER LENGTH GRANULARITY */ + DSET16(&data[6], blocks); + /* MAXIMUM TRANSFER LENGTH in blocks Blocksize = spec->blocklen, max length = spec->blocklen*max_blocks*/ + uint32_t max_blocks = conn->MaxBurstLength/(uint32_t)spec->blocklen + 1; + DSET32(&data[8], max_blocks);/* While changing this value keep track of iobuf boundaries */ + /* OPTIMAL TRANSFER LENGTH */ + if (spec->opt_tlen == 0 || spec->rsize == 0) { + blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen; + } else { + blocks = spec->lb_per_rec * spec->opt_tlen; + if (blocks == 0) //this would not happen + blocks = 1; + if ((blocks * (uint32_t)spec->blocklen) > ISTGT_LU_WORK_BLOCK_SIZE) { + blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen; + } + } + DSET32(&data[12], blocks); + /* MAXIMUM PREFETCH XDREAD XDWRITE TRANSFER LENGTH */ + DSET32(&data[16], 0); + len = 20 - hlen; + + if (spec->unmap) { + /* MAXIMUM UNMAP LBA COUNT */ + unsigned int max_unmap_sectors = spec->max_unmap_sectors; + DSET32(&data[20], max_unmap_sectors); + /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT */ + data[24] = 0xFF; + data[25] = 0xFF; + data[26] = 0xFF; + data[27] = 0xFF; + len = 27 - hlen; + + /* OPTIMAL UNMAP GRANULARITY */ + DSET32(&data[28], spec->lb_per_rec); + + /* UNMAP GRANULARITY ALIGNMENT & UGAVALID(7) */ + data[32] = 0x80; + data[33] = 0; data[34] = 0; data[35] = 0; + + /* MAXIMUM WRITE SAME LENGTH */ + DSET64(&data[36], 0); /* no limit */ + /* Reserved */ + memset(&data[44], 0x00, 64-44); + len = 64 - hlen; + } else { + /* MAXIMUM UNMAP LBA COUNT */ + DSET32(&data[20], 0); /* not implement UNMAP */ + /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT */ + DSET32(&data[24], 0); /* not implement UNMAP */ + /* OPTIMAL UNMAP GRANULARITY */ + DSET32(&data[28], 0); /* not specified */ + /* UNMAP GRANULARITY ALIGNMENT */ + DSET32(&data[32], (0 & 0x7fffffffU)); + /* UGAVALID(7) */ + BDADD8(&data[32], 0, 7); /* not valid ALIGNMENT */ + /* MAXIMUM WRITE SAME LENGTH */ + DSET64(&data[36], 0); /* no limit */ + /* Reserved */ + memset(&data[44], 0x00, 64-44); + len = 64 - hlen; + } + + DSET16(&data[2], len); + break; + + case 0xb1: /* SBC Block Device Characteristics */ + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* MEDIUM ROTATION RATE */ + //DSET16(&data[4], 0x0000); /* not reported */ + //DSET16(&data[4], 0x0001); /* Non-rotating medium (solid state) */ + //DSET16(&data[4], 5400); /* rotation rate (5400rpm) */ + //DSET16(&data[4], 7200); /* rotation rate (7200rpm) */ + //DSET16(&data[4], 10000); /* rotation rate (10000rpm) */ + //DSET16(&data[4], 15000); /* rotation rate (15000rpm) */ + if (spec->unmap) { + DSET16(&data[4], 0x0001); + } else { + DSET16(&data[4], spec->lu->lun[spec->lun].rotationrate); + } + /* Reserved */ + data[6] = 0; + /* NOMINAL FORM FACTOR(3-0) */ + //BDSET8W(&data[7], 0x00, 3, 4); /* not reported */ + //BDSET8W(&data[7], 0x01, 3, 4); /* 5.25 inch */ + //BDSET8W(&data[7], 0x02, 3, 4); /* 3.5 inch */ + //BDSET8W(&data[7], 0x03, 3, 4); /* 2.5 inch */ + //BDSET8W(&data[7], 0x04, 3, 4); /* 1.8 inch */ + //BDSET8W(&data[7], 0x05, 3, 4); /* less 1.8 inch */ + BDSET8W(&data[7], spec->lu->lun[spec->lun].formfactor, 3, 4); + /* Reserved */ + memset(&data[8], 0x00, 64-8); + + len = 64 - hlen; + DSET16(&data[2], len); + break; + + case 0xb2: /* SBC Thin Provisioning */ + if (!spec->unmap) { + ISTGT_ERRLOG("c#%d unsupported INQUIRY VPD page 0x%x\n", conn->id, pc); + return -1; + } + + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* PAGE CODE */ + data[1] = pc; + /* PAGE LENGTH */ + DSET16(&data[2], 0); + hlen = 4; + + /* THRESHOLD EXPONENT */ + data[4] = 0; + /* DP(0) */ + //BDSET8(&data[5], 0, 0); + //if (spec->unmap && spec->wsame) + // data[5] = 0xE0; //LBPU unmap command; LBPWS, LBPWS10- write_same with unmap bit + //else + if (spec->unmap) + data[5] = 0x80; + else + data[5] = 0; + + /* Reserved */ + data[6] = 0x02; //010: thin provisioned, 001: resource provisioned + data[7] = 0; + len = 8 - hlen; +#if 0 + /* XXX not yet */ + /* PROVISIONING GROUP DESCRIPTOR ... */ + DSET16(&data[8], 0); + len = 8 - hlen; +#endif + + DSET16(&data[2], len); + break; + + default: + if (pc >= 0xc0 && pc <= 0xff) { + ISTGT_WARNLOG("c#%d Vendor specific INQUIRY VPD page 0x%x\n", conn->id, pc); + } else { + ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc); + } + return -1; + } + } else { + /* Standard INQUIRY data */ + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], pq, 7, 3); + BDADD8W(&data[0], pd, 4, 5); + /* RMB(7) */ + BDSET8W(&data[1], rmb, 7, 1); + /* VERSION */ + /* See SPC3/SBC2/MMC4/SAM2 for more details */ + data[2] = SPC_VERSION_SPC3; + /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */ + BDSET8W(&data[3], 2, 3, 4); /* format 2 */ + BDADD8(&data[1], 1, 4); /* hierarchical support */ + /* ADDITIONAL LENGTH */ + data[4] = 0; + hlen = 5; + + /* SCCS(7) ACC(6) TPGS(5-4) 3PC(3) PROTECT(0) */ + data[5] = 0; + //BDADD8W(&data[5], 1, 7, 1); /* storage array controller */ + BDADD8W(&data[5], 0x00, 5, 2); /* Not support TPGS */ + if (spec->xcopy == 1) { + BDADD8(&data[5], 1, 3); /* support 3PC EXTETNDED COPY */ + } + //BDADD8W(&data[5], 0x01, 5, 2); /* Only implicit */ + //BDADD8W(&data[5], 0x02, 5, 2); /* Only explicit */ + //BDADD8W(&data[5], 0x03, 5, 2); /* Both explicit and implicit */ + /* BQUE(7) ENCSERV(6) VS(5) MULTIP(4) MCHNGR(3) ADDR16(0) */ + data[6] = 0; + BDADD8W(&data[6], 1, 4, 1); /* MULTIP */ + /* WBUS16(5) SYNC(4) LINKED(3) CMDQUE(1) VS(0) */ + data[7] = 0; + if (spec->queue_depth != 0) { + BDADD8(&data[7], 1, 1); /* CMDQUE */ + } + /* T10 VENDOR IDENTIFICATION */ + istgt_strcpy_pad(&data[8], 8, spec->lu->inq_vendor, ' '); + /* PRODUCT IDENTIFICATION */ + istgt_strcpy_pad(&data[16], 16, spec->lu->inq_product, ' '); + /* PRODUCT REVISION LEVEL */ + istgt_strcpy_pad(&data[32], 4, spec->lu->inq_revision, ' '); + /* Vendor specific */ + memset(&data[36], 0x20, 20); + /* CLOCKING(3-2) QAS(1) IUS(0) */ + data[56] = 0; + /* Reserved */ + data[57] = 0; + /* VERSION DESCRIPTOR 1-8 */ + DSET16(&data[58], 0x0960); /* iSCSI (no version claimed) */ + DSET16(&data[60], 0x0300); /* SPC-3 (no version claimed) */ + DSET16(&data[62], 0x0320); /* SBC-2 (no version claimed) */ + DSET16(&data[64], 0x0040); /* SAM-2 (no version claimed) */ + DSET16(&data[66], 0x0000); + DSET16(&data[68], 0x0000); + DSET16(&data[70], 0x0000); + DSET16(&data[72], 0x0000); + /* Reserved[74-95] */ + memset(&data[74], 0, (96 - 74)); + /* Vendor specific parameters[96-n] */ + //data[96] = 0; + len = 96 - hlen; + + /* ADDITIONAL LENGTH */ + data[4] = len; + } + + return hlen + len; +} + +#define MODE_SENSE_PAGE_INIT(B,L,P,SP) \ + do { \ + memset((B), 0, (L)); \ + if ((SP) != 0x00) { \ + (B)[0] = (P) | 0x40; /* PAGE + SPF=1 */ \ + (B)[1] = (SP); \ + DSET16(&(B)[2], (L) - 4); \ + } else { \ + (B)[0] = (P); \ + (B)[1] = (L) - 2; \ + } \ + } while (0) + +static int +istgt_lu_disk_scsi_mode_sense_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len) +{ + uint8_t *cp; + int len = 0; + int plen; + int rc; + int i; + +#if 0 + printf("pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage); +#endif +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage); +#endif + + if (pc == 0x00) { + /* Current values */ + } else if (pc == 0x01) { + /* Changeable values */ + if (page != 0x08) { + /* not supported */ + return -1; + } + } else if (pc == 0x02) { + /* Default values */ + } else { + /* Saved values */ + } + + cp = &data[len]; + switch (page) { + case 0x00: + /* Vendor specific */ + break; + case 0x01: + /* Read-Write Error Recovery */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Read-Write Error Recovery\n", conn->id); + if (subpage != 0x00) + break; + plen = 0x0a + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x02: + /* Disconnect-Reconnect */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Disconnect-Reconnect\n", conn->id); + if (subpage != 0x00) + break; + plen = 0x0e + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x03: + /* Obsolete (Format Device) */ + break; + case 0x04: + /* Obsolete (Rigid Disk Geometry) */ + break; + case 0x05: + /* Obsolete (Rigid Disk Geometry) */ + break; + case 0x06: + /* Reserved */ + break; + case 0x07: + /* Verify Error Recovery */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Verify Error Recovery\n", conn->id); + if (subpage != 0x00) + break; + plen = 0x0a + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x08: + /* Caching */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Caching\n", conn->id); + if (subpage != 0x00) + break; + + plen = 0x12 + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + BDADD8(&cp[0], 1, 7); /* PS */ + if (pc == 0x01) { + // Changeable values + BDADD8(&cp[2], 1, 2); /* WCE */ + BDADD8(&cp[2], 1, 0); /* RCD */ + len += plen; + break; + } + BDADD8(&cp[2], 1, 2); /* WCE */ + //BDADD8(&cp[2], 1, 0); /* RCD */ + { + int fd; + fd = spec->fd; + rc = fcntl(fd , F_GETFL, 0); + if (rc != -1 && !(rc & O_FSYNC)) { + BDADD8(&cp[2], 1, 2); /* WCE=1 */ + } else { + BDADD8(&cp[2], 0, 2); /* WCE=0 */ + } + } + if (spec->readcache) { + BDADD8(&cp[2], 0, 0); /* RCD=0 */ + } else { + BDADD8(&cp[2], 1, 0); /* RCD=1 */ + } + len += plen; + break; + case 0x09: + /* Obsolete */ + break; + case 0x0a: + switch (subpage) { + case 0x00: + /* Control */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Control\n", conn->id); + plen = 0x0a + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x01: + /* Control Extension */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Control Extension\n", conn->id); + plen = 0x1c + 4; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0xff: + /* All subpages */ + len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x00, &data[len], alloc_len); + len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x01, &data[len], alloc_len); + break; + default: + /* 0x02-0x3e: Reserved */ + break; + } + break; + case 0x0b: + /* Obsolete (Medium Types Supported) */ + break; + case 0x0c: + /* Obsolete (Notch And Partitio) */ + break; + case 0x0d: + /* Obsolete */ + break; + case 0x0e: + case 0x0f: + /* Reserved */ + break; + case 0x10: + /* XOR Control */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE XOR Control\n", conn->id); + if (subpage != 0x00) + break; + plen = 0x16 + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x11: + case 0x12: + case 0x13: + /* Reserved */ + break; + case 0x14: + /* Enclosure Services Management */ + break; + case 0x15: + case 0x16: + case 0x17: + /* Reserved */ + break; + case 0x18: + /* Protocol-Specific LUN */ +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific LUN\n"); + if (subpage != 0x00) + break; + plen = 0x04 + 0x00 + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; +#endif + break; + case 0x19: + /* Protocol-Specific Port */ +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific Port\n"); + if (subpage != 0x00) + break; + plen = 0x04 + 0x00 + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; +#endif + break; + case 0x1a: + /* Power Condition */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Power Condition\n", conn->id); + if (subpage != 0x00) + break; + plen = 0x0a + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x1b: + /* Reserved */ + break; + case 0x1c: + /* Informational Exceptions Control */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SENSE Informational Exceptions Control\n", conn->id); + if (subpage != 0x00) + break; + + plen = 0x0a + 2; + MODE_SENSE_PAGE_INIT(cp, plen, page, subpage); + len += plen; + break; + case 0x1d: + case 0x1e: + case 0x1f: + /* Reserved */ + break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + /* Vendor-specific */ + break; + case 0x3f: + switch (subpage) { + case 0x00: + /* All mode pages */ + for (i = 0x00; i < 0x3e; i ++) { + len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len); + } + break; + case 0xff: + /* All mode pages and subpages */ + for (i = 0x00; i < 0x3e; i ++) { + len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len); + } + for (i = 0x00; i < 0x3e; i ++) { + len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len); + } + break; + default: + /* 0x01-0x3e: Reserved */ + break; + } + } + + return len; +} + +static int +istgt_lu_disk_scsi_mode_sense6(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len) +{ + uint8_t *cp; + int hlen = 0, len = 0, plen; + int total; + int llbaa = 0; + + data[0] = 0; /* Mode Data Length */ + data[1] = 0; /* Medium Type */ + data[2] = 0; /* Device-Specific Parameter */ + if (spec->dpofua) { + BDADD8(&data[2], 1, 4); /* DPOFUA */ + } + if (spec->lu->readonly) { + BDADD8(&data[2], 1, 7); /* WP */ + } + data[3] = 0; /* Block Descripter Length */ + hlen = 4; + + cp = &data[4]; + if (dbd) { /* Disable Block Descripters */ + len = 0; + } else { + if (llbaa) { + /* Number of Blocks */ + DSET64(&cp[0], spec->blockcnt); + /* Reserved */ + DSET32(&cp[8], 0); + /* Block Length */ + DSET32(&cp[12], (uint32_t) spec->blocklen); + len = 16; + } else { + /* Number of Blocks */ + if (spec->blockcnt > 0xffffffffULL) { + DSET32(&cp[0], 0xffffffffUL); + } else { + DSET32(&cp[0], (uint32_t) spec->blockcnt); + } + /* Block Length */ + DSET32(&cp[4], (uint32_t) spec->blocklen); + len = 8; + } + cp += len; + } + data[3] = len; /* Block Descripter Length */ + + plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len); + if (plen < 0) { + return -1; + } + cp += plen; + + total = hlen + len + plen; + data[0] = total - 1; /* Mode Data Length */ + + return total; +} + +static int +istgt_lu_disk_scsi_mode_sense10(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int llbaa, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len) +{ + uint8_t *cp; + int hlen = 0, len = 0, plen; + int total; + + DSET16(&data[0], 0); /* Mode Data Length */ + data[2] = 0; /* Medium Type */ + data[3] = 0; /* Device-Specific Parameter */ + if (spec->dpofua) { + BDADD8(&data[3], 1, 4); /* DPOFUA */ + } + if (spec->lu->readonly) { + BDADD8(&data[3], 1, 7); /* WP */ + } + if (llbaa) { + BDSET8(&data[4], 1, 1); /* Long LBA */ + } else { + BDSET8(&data[4], 0, 1); /* Short LBA */ + } + data[5] = 0; /* Reserved */ + DSET16(&data[6], 0); /* Block Descripter Length */ + hlen = 8; + + cp = &data[8]; + if (dbd) { /* Disable Block Descripters */ + len = 0; + } else { + if (llbaa) { + /* Number of Blocks */ + DSET64(&cp[0], spec->blockcnt); + /* Reserved */ + DSET32(&cp[8], 0); + /* Block Length */ + DSET32(&cp[12], (uint32_t) spec->blocklen); + len = 16; + } else { + /* Number of Blocks */ + if (spec->blockcnt > 0xffffffffULL) { + DSET32(&cp[0], 0xffffffffUL); + } else { + DSET32(&cp[0], (uint32_t) spec->blockcnt); + } + /* Block Length */ + DSET32(&cp[4], (uint32_t) spec->blocklen); + len = 8; + } + cp += len; + } + DSET16(&data[6], len); /* Block Descripter Length */ + + plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len); + if (plen < 0) { + return -1; + } + cp += plen; + + total = hlen + len + plen; + DSET16(&data[0], total - 2); /* Mode Data Length */ + + return total; +} + +int +istgt_lu_disk_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, size_t len) +{ + int rc; + + if (lu_cmd->lu->queue_depth == 0) { + rc = istgt_iscsi_transfer_out(conn, lu_cmd, len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d iscsi_transfer_out()\n", conn->id); + return -1; + } + } + return 0; +} + +static int +istgt_lu_disk_scsi_mode_select_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pf, int sp, uint8_t *data, size_t len) +{ + size_t hlen, plen; + int spf, page, subpage; + int rc; + const char *msgwce = NULL; + const char *msgrcd = NULL; + if (pf == 0) { + /* vendor specific */ + return 0; + } + + if (len < 1) + return 0; + spf = BGET8(&data[0], 6); + page = data[0] & 0x3f; + if (spf) { + /* Sub_page mode page format */ + hlen = 4; + if (len < hlen) + return 0; + subpage = data[1]; + + plen = DGET16(&data[2]); + } else { + /* Page_0 mode page format */ + hlen = 2; + if (len < hlen) + return 0; + subpage = 0; + plen = data[1]; + } + plen += hlen; + if (len < plen) + return 0; + +#if 0 + printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage); +#endif + switch (page) { + case 0x08: + /* Caching */ + { + int wce, rcd; + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SELECT Caching\n", conn->id); + if (subpage != 0x00) + break; + if (plen != 0x12 + hlen) { + /* unknown format */ + break; + } + wce = BGET8(&data[2], 2); /* WCE */ + rcd = BGET8(&data[2], 0); /* RCD */ + + { + int fd; + fd = spec->fd; + rc = fcntl(fd , F_GETFL, 0); + if (rc != -1) { + if (wce) { + msgwce = "WCE"; + rc = fcntl(fd, F_SETFL, (rc & ~O_FSYNC)); + spec->writecache = 1; + } else { + msgwce = "WCE-off"; + rc = fcntl(fd, F_SETFL, (rc | O_FSYNC)); + spec->writecache = 0; + } + if (rc == -1) { + /* XXX */ + //ISTGT_ERRLOG("fcntl(F_SETFL) failed\n"); + } + } + } + if (rcd) { + msgrcd = "RCD"; + spec->readcache = 0; + } else { + msgrcd = "RCD-off"; + spec->readcache = 1; + } + } + break; + default: + /* not supported */ + break; + } + + len -= plen; + if (len != 0) { + rc = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[plen], len); + if (rc < 0) { + if (msgwce || msgrcd) { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SELECT %s %s (error..)\n", conn->id, msgwce, msgrcd); + } + return rc; + } + } + if (msgwce || msgrcd) { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE_SELECT %s %s\n", conn->id, msgwce, msgrcd); + } + return 0; +} + +static int +istgt_lu_disk_scsi_read_defect10(ISTGT_LU_DISK *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int req_plist, int req_glist, int list_format, uint8_t *data, int alloc_len) +{ + int hlen = 0, len = 0; + int total; + + if (alloc_len < 4) { + return -1; + } + + data[0] = 0; /* Reserved */ + data[1] = 0; + if (req_plist) { + BDADD8(&data[1], 1, 4); /* PLISTV */ + } + if (req_glist) { + BDADD8(&data[1], 1, 3); /* GLISTV */ + } + BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */ + DSET16(&data[2], 0); /* DEFECT LIST LENGTH */ + hlen = 4; + + /* defect list (if any) */ + len = 0; + + total = hlen + len; + DSET16(&data[2], total - hlen); /* DEFECT LIST LENGTH */ + return total; +} + +static int +istgt_lu_disk_scsi_read_defect12(ISTGT_LU_DISK *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int req_plist, int req_glist, int list_format, uint8_t *data, int alloc_len) +{ + int hlen = 0, len = 0; + int total; + + if (alloc_len < 8) { + return -1; + } + + data[0] = 0; /* Reserved */ + data[1] = 0; + if (req_plist) { + BDADD8(&data[1], 1, 4); /* PLISTV */ + } + if (req_glist) { + BDADD8(&data[1], 1, 3); /* GLISTV */ + } + BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */ + data[2] = 0; /* Reserved */ + data[3] = 0; /* Reserved */ + DSET32(&data[4], 0); /* DEFECT LIST LENGTH */ + hlen = 8; + + /* defect list (if any) */ + len = 0; + + total = hlen + len; + DSET32(&data[4], total - hlen); /* DEFECT LIST LENGTH */ + return total; +} + +static int +istgt_lu_disk_scsi_report_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb __attribute__((__unused__)), uint8_t *data, int alloc_len) +{ + ISTGT_Ptr istgt; + ISTGT_LU_Ptr lu; + uint8_t *cp; + uint8_t *cp_count; + int hlen = 0, len = 0, plen; + int total; + int pg_tag; + int nports; + int i, j, k; + int ridx; + + if (alloc_len < 0xfff) { + return -1; + } + + istgt = conn->istgt; + lu = spec->lu; + + /* RETURN DATA LENGTH */ + DSET32(&data[0], 0); + hlen = 4; + + MTX_LOCK(&istgt->mutex); + for (i = 0; i < lu->maxmap; i++) { + pg_tag = lu->map[i].pg_tag; + /* skip same pg_tag */ + for (j = 0; j < i; j++) { + if (lu->map[j].pg_tag == pg_tag) { + goto skip_pg_tag; + } + } + + /* Target port group descriptor N */ + cp = &data[hlen + len]; + + /* PREF(7) ASYMMETRIC ACCESS STATE(3-0) */ + cp[0] = 0; + BDSET8(&cp[0], 1, 7); /* PREF */ + switch (lu->map[j].pg_aas & 0x0f) { + case AAS_ACTIVE_OPTIMIZED: + BDADD8W(&cp[0], AAS_ACTIVE_OPTIMIZED, 3, 4); + break; + case AAS_ACTIVE_NON_OPTIMIZED: + BDADD8W(&cp[0], AAS_ACTIVE_NON_OPTIMIZED, 3, 4); + break; + case AAS_STANDBY: + BDADD8W(&cp[0], AAS_STANDBY, 3, 4); + break; + case AAS_UNAVAILABLE: + BDADD8W(&cp[0], AAS_UNAVAILABLE, 3, 4); + break; + case AAS_TRANSITIONING: + BDADD8W(&cp[0], AAS_TRANSITIONING, 3, 4); + break; + default: + ISTGT_ERRLOG("c#%d unsupported AAS\n", conn->id); + break; + } + /* T_SUP(7) U_SUP(3) S_SUP(2) S_SUP AN_SUP(1) AO_SUP(0) */ + cp[1] = 0; + //BDADD8(&cp[1], 1, 7); /* transitioning supported */ + //BDADD8(&cp[1], 1, 3); /* unavailable supported */ + //BDADD8(&cp[1], 1, 2); /* standby supported */ + BDADD8(&cp[1], 1, 1); /* active/non-optimized supported */ + BDADD8(&cp[1], 1, 0); /* active/optimized supported */ + /* TARGET PORT GROUP */ + DSET16(&cp[2], pg_tag); + /* Reserved */ + cp[4] = 0; + /* STATUS CODE */ + if (lu->map[j].pg_aas & AAS_STATUS_IMPLICIT) { + cp[5] = 0x02; /* by implicit */ + } else if (lu->map[j].pg_aas & AAS_STATUS_STPG) { + cp[5] = 0x01; /* by SET TARGET PORT GROUPS */ + } else { + cp[5] = 0; /* No status */ + } + /* Vendor specific */ + cp[6] = 0; + /* TARGET PORT COUNT */ + cp[7] = 0; + cp_count = &cp[7]; + plen = 8; + len += plen; + + nports = 0; + ridx = 0; + MTX_LOCK(&istgt->mutex); + for (j = 0; j < istgt->nportal_group; j++) { + if (istgt->portal_group[j].tag == pg_tag) { + for (k = 0; k < istgt->portal_group[j].nportals; k++) { + /* Target port descriptor(s) */ + cp = &data[hlen + len]; + /* Obsolete */ + DSET16(&cp[0], 0); + /* RELATIVE TARGET PORT IDENTIFIER */ + DSET16(&cp[2], (uint16_t) (1 + ridx)); + plen = 4; + len += plen; + nports++; + ridx++; + } + } else { + ridx += istgt->portal_group[j].nportals; + } + } + MTX_UNLOCK(&istgt->mutex); + + if (nports > 0xff) { + ISTGT_ERRLOG("c#%d too many portals in portal group\n", conn->id); + MTX_UNLOCK(&istgt->mutex); + return -1; + } + + /* TARGET PORT COUNT */ + cp_count[0] = nports; + + skip_pg_tag: + ; + } + MTX_UNLOCK(&istgt->mutex); + + total = hlen + len; + if (total > alloc_len) { + ISTGT_ERRLOG("c#%d alloc_len(%d) too small\n", conn->id, alloc_len); + return -1; + } + + /* RETURN DATA LENGTH */ + DSET32(&data[0], total - 4); + + return total; +} + +static int +istgt_lu_disk_scsi_set_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int len) +{ + ISTGT_LU_Ptr lu; + int pg_tag; + int aas; + int pg; + int rc; + int i; + + if (len < 4) { + return -1; + } + + lu = spec->lu; + + aas = BGET8W(&data[0], 3, 4); + pg = DGET16(&data[2]); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d AAS=0x%x, PG=0x%4.4x\n", conn->id, aas, pg); + + for (i = 0; i < lu->maxmap; i++) { + pg_tag = lu->map[i].pg_tag; + if (pg != pg_tag) + continue; + + switch (aas) { + case AAS_ACTIVE_OPTIMIZED: + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d Active/optimized\n", conn->id); + break; + case AAS_ACTIVE_NON_OPTIMIZED: + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d Active/non-optimized\n", conn->id); + break; +#if 0 + case AAS_STANDBY: + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Standby\n"); + break; + case AAS_UNAVAILABLE: + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Unavailable\n"); + break; +#endif + case AAS_TRANSITIONING: + return -1; + default: + ISTGT_ERRLOG("c#%d nsupported AAS 0x%x\n", conn->id, aas); + return -1; + } + lu->map[i].pg_aas = aas; + lu->map[i].pg_aas |= AAS_STATUS_STPG; + } + + len -=4; + if (len != 0) { + rc = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, data, len); + if (rc < 0) { + return rc; + } + } + return 0; +} + +int +istgt_lu_disk_add_nexus(ISTGT_LU_Ptr lu, int lun, const char *initiator_port) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + int rc = 0; + + spec = lu->lun[lun].spec; + if (spec == NULL) + return 0; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_add_nexus: LU%d, LUN%d, Initiator %s\n", lu->num, lun, initiator_port); + + /* Find the nexus */ + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + /* Retrun if nexus is already added */ + if (strcasecmp(nexus->initiator_port, initiator_port) == 0){ + return 0; + } + } + + nexus = xmalloc(sizeof *nexus); + if (nexus == NULL) { + ISTGT_ERRLOG("istgt_lu_disk_add_nexus: ENOMEM\n"); + goto error_return; + } + nexus->initiator_port = initiator_port; + nexus->ua_pending &= ISTGT_UA_NONE; + rc = pthread_mutex_init(&nexus->nexus_mutex, &lu->istgt->mutex_attr); + if (rc != 0) { + ISTGT_ERRLOG("mutex_init() failed\n"); + goto error_return; + } + TAILQ_INSERT_TAIL(&spec->nexus, nexus, nexus_next); + + return 0; + error_return: + return -2; +} + +int +istgt_lu_disk_remove_nexus(ISTGT_LU_Ptr lu, int lun, const char *initiator_port) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus, *tmp_nexus; + int rc = 0; + + spec = lu->lun[lun].spec; + if (spec == NULL) + return 0; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_remove_nexus: LU%d LUN%d Initiator %s\n", lu->num, lun, initiator_port); + + TAILQ_FOREACH_SAFE(nexus, &spec->nexus, nexus_next, tmp_nexus) { + if (nexus == NULL) + break; + if (strcasecmp(nexus->initiator_port, initiator_port) == 0) { + TAILQ_REMOVE(&spec->nexus, nexus, nexus_next); + rc = pthread_mutex_destroy(&nexus->nexus_mutex); + if (rc != 0) { + /* Ignore Error */ + ISTGT_ERRLOG("mutex_destroy() failed\n"); + } + xfree(nexus); + return 0; + } + } + return 0; +} + +void +istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey) +{ + int i; + + if (prkey == NULL) + return; + xfree(prkey->registered_initiator_port); + prkey->registered_initiator_port = NULL; + xfree(prkey->registered_target_port); + prkey->registered_target_port = NULL; + prkey->pg_idx = 0; + prkey->pg_tag = 0; + for (i = 0; i < prkey->ninitiator_ports; i++) { + xfree(prkey->initiator_ports[i]); + prkey->initiator_ports[i] = NULL; + } + xfree(prkey->initiator_ports); + prkey->initiator_ports = NULL; + prkey->all_tpg = 0; + prkey->ninitiator_ports = 0; +} + +static ISTGT_LU_PR_KEY * +istgt_lu_disk_find_pr_key(ISTGT_LU_DISK *spec, const char *initiator_port, const char *target_port, uint64_t key) +{ + ISTGT_LU_PR_KEY *prkey; + int i; + + /* return pointer if I_T nexus is registered */ +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "find prkey=0x%16.16"PRIx64", port=%s\n", + key, ((initiator_port != NULL) ? initiator_port : "N/A")); +#endif /* ISTGT_TRACE_DISK */ + + if (initiator_port == NULL) + return NULL; + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + if (prkey == NULL) + continue; +#ifdef ISTGT_TRACE_DISK + if (key != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "prkey=0x%16.16"PRIx64"\n", + prkey->key); + } +#endif /* ISTGT_TRACE_DISK */ + if ((key != 0 && prkey->key != key) || (prkey->key == 0)) + continue; + +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pript=%s, ipt=%s\n", + prkey->registered_initiator_port, + initiator_port); +#endif /* ISTGT_TRACE_DISK */ + if (strcmp(prkey->registered_initiator_port, + initiator_port) == 0) { +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "prtpt=%s, tpt=%s\n", + prkey->registered_target_port, + target_port); +#endif /* ISTGT_TRACE_DISK */ + if (prkey->all_tpg != 0 + || target_port == NULL + || strcmp(prkey->registered_target_port, + target_port) == 0) { + return prkey; + } + } + } + return NULL; +} + +static int +istgt_lu_disk_remove_other_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), const char *initiator_port, const char *target_port, uint64_t key) +{ + ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2; + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "remove other prkey=0x%16.16"PRIx64", port=%s\n", + key, ((initiator_port != NULL) ? initiator_port : "N/A")); + + for (i = 0; i < spec->npr_keys; ) { + prkey = &spec->pr_keys[i]; + if (prkey == NULL){ + i++; + continue; + } + if (key == 0 || prkey->key == key){ + i++; + continue; + } + if (initiator_port == NULL || + strcasecmp(prkey->registered_initiator_port, + initiator_port) == 0){ + i++; + continue; + } + if (prkey->all_tpg != 0 + || target_port == NULL + || strcasecmp(prkey->registered_target_port, + target_port) == 0) { + i++; + continue; + } + + istgt_lu_disk_free_pr_key(prkey); + for (j = i; j < spec->npr_keys - 1; j++) { + prkey1 = &spec->pr_keys[j]; + prkey2 = &spec->pr_keys[j+1]; + + prkey1->key = prkey2->key; + prkey2->key = 0; + prkey1->registered_initiator_port + = prkey2->registered_initiator_port; + prkey2->registered_initiator_port = NULL; + prkey1->registered_target_port + = prkey2->registered_target_port; + prkey2->registered_target_port = NULL; + prkey1->pg_idx = prkey2->pg_idx; + prkey2->pg_idx = 0; + prkey1->pg_tag = prkey2->pg_tag; + prkey2->pg_tag = 0; + prkey1->ninitiator_ports = prkey2->ninitiator_ports; + prkey2->ninitiator_ports = 0; + prkey1->initiator_ports = prkey2->initiator_ports; + prkey2->initiator_ports = NULL; + prkey1->all_tpg = prkey2->all_tpg; + prkey2->all_tpg = 0; + } + spec->npr_keys--; + } + return 0; +} + +static int +istgt_lu_disk_remove_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), const char *initiator_port, const char *target_port, uint64_t key) +{ + ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2; + int i, j; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "remove prkey=0x%16.16"PRIx64", port=%s\n", + key, ((initiator_port != NULL) ? initiator_port : "N/A")); + + for (i = 0; i < spec->npr_keys; ) { + prkey = &spec->pr_keys[i]; + if (prkey == NULL || prkey->key == 0){ + i++; + continue; + } + if (key != 0 && prkey->key != key){ + i++; + continue; + } + if (initiator_port != NULL + && strcasecmp(prkey->registered_initiator_port, + initiator_port) != 0){ + i++; + continue; + } + if (prkey->all_tpg == 0 + && target_port != NULL + && strcasecmp(prkey->registered_target_port, + target_port) != 0){ + i++; + continue; + } + + istgt_lu_disk_free_pr_key(prkey); + for (j = i; j < spec->npr_keys - 1; j++) { + prkey1 = &spec->pr_keys[j]; + prkey2 = &spec->pr_keys[j+1]; + + prkey1->key = prkey2->key; + prkey2->key = 0; + prkey1->registered_initiator_port + = prkey2->registered_initiator_port; + prkey2->registered_initiator_port = NULL; + prkey1->registered_target_port + = prkey2->registered_target_port; + prkey2->registered_target_port = NULL; + prkey1->pg_idx = prkey2->pg_idx; + prkey2->pg_idx = 0; + prkey1->pg_tag = prkey2->pg_tag; + prkey2->pg_tag = 0; + prkey1->ninitiator_ports = prkey2->ninitiator_ports; + prkey2->ninitiator_ports = 0; + prkey1->initiator_ports = prkey2->initiator_ports; + prkey2->initiator_ports = NULL; + prkey1->all_tpg = prkey2->all_tpg; + prkey2->all_tpg = 0; + } + spec->npr_keys--; + } + return 0; +} + +static int +istgt_lu_parse_transport_id(char **tid, uint8_t *data, int len) +{ + int fc, pi; + int hlen, plen; + + if (tid == NULL) + return -1; + if (data == NULL) + return -1; + + fc = BGET8W(&data[0], 7, 2); + pi = BGET8W(&data[0], 3, 4); + if (fc != 0) { + ISTGT_ERRLOG("FORMAT CODE != 0\n"); + return -1; + } + if (pi != SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME) { + ISTGT_ERRLOG("PROTOCOL IDENTIFIER != ISCSI\n"); + return -1; + } + + /* PROTOCOL IDENTIFIER = 0x05 */ + hlen = 4; + /* ADDITIONAL LENGTH */ + plen = DGET16(&data[2]); + if (plen > len) { + ISTGT_ERRLOG("invalid length %d (expected %d)\n", + plen, len); + return -1; + } + if (plen > MAX_ISCSI_NAME) { + ISTGT_ERRLOG("invalid length %d (expected %d)\n", + plen, MAX_ISCSI_NAME); + return -1; + } + + /* ISCSI NAME */ + *tid = xmalloc(plen + 1); + memcpy(*tid, data, plen); + (*tid)[plen] = '\0'; + strlwr(*tid); + + return hlen + plen; +} + +static int +istgt_lu_disk_scsi_persistent_reserve_in(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, int sa, uint8_t *data, int alloc_len __attribute__((__unused__))) +{ + ISTGT_LU_PR_KEY *prkey; + size_t hlen = 0, len = 0, plen; + uint8_t *cp; + int total; + int i; + + cp = &data[hlen + len]; + total = 0; + switch (sa) { + case 0x00: /* READ KEYS */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ KEYS\n", conn->id); + + /* PRGENERATION */ + DSET32(&data[0], spec->pr_generation); + /* ADDITIONAL LENGTH */ + DSET32(&data[4], 0); + hlen = 8; + + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + /* reservation key N */ + cp = &data[hlen + len]; + DSET64(&cp[0], prkey->key); + len += 8; + } + total = hlen + len; + /* ADDITIONAL LENGTH */ + DSET32(&data[4], total - hlen); + break; + + case 0x01: /* READ RESERVATION */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ RESERVATION\n", conn->id); + + /* PRGENERATION */ + DSET32(&data[0], spec->pr_generation); + /* ADDITIONAL LENGTH */ + DSET32(&data[4], 0); + hlen = 8; + + if (spec->rsv_key != 0) { + /* RESERVATION KEY */ + DSET64(&data[8], spec->rsv_key); + /* Obsolete */ + DSET32(&data[16], 0); + /* Reserved */ + data[20] = 0; + /* SCOPE(7-4) TYPE(3-0) */ + BDSET8W(&data[21], spec->rsv_scope, 7, 4); + BDADD8W(&data[21], spec->rsv_type, 3, 4); + /* Obsolete */ + DSET16(&data[22], 0); + len = 24 - hlen; + } + + total = hlen + len; + /* ADDITIONAL LENGTH */ + DSET32(&data[4], total - hlen); + break; + + case 0x02: /* REPORT CAPABILITIES */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d REPORT CAPABILITIES\n", conn->id); + + /* LENGTH */ + DSET16(&data[0], 0x0008); + /* CRH(4) SIP_C(3) ATP_C(2) PTPL_C(0) */ + data[2] = 0; + //BDADD8(&data[2], 1, 4); /* Compatible Reservation Handling */ + BDADD8(&data[2], 1, 3); /* Specify Initiator Ports Capable */ + BDADD8(&data[2], 1, 2); /* All Target Ports Capable */ + //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Capable */ + /* TMV(7) PTPL_A(0) */ + data[3] = 0; + //BDADD8(&data[2], 1, 7); /* Type Mask Valid */ + //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Activated */ + /* PERSISTENT RESERVATION TYPE MASK */ + DSET16(&data[4], 0); + /* Reserved */ + DSET16(&data[6], 0); + hlen = 8; + + total = hlen + len; + break; + + case 0x03: /* READ FULL STATUS */ + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ FULL STATUS\n", conn->id); + + /* PRGENERATION */ + DSET32(&data[0], spec->pr_generation); + /* ADDITIONAL LENGTH */ + DSET32(&data[4], 0); + hlen = 8; + + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + /* Full status descriptors N */ + cp = &data[hlen + len]; + + /* RESERVATION KEY */ + DSET64(&cp[0], prkey->key); + /* Reserved */ + DSET64(&cp[8], 0); + /* ALL_TG_PT(1) R_HOLDER(0) */ + cp[12] = 0; + if (prkey->all_tpg) { + BDADD8(&cp[12], 1, 1); + } + /* SCOPE(7-4) TYPE(3-0) */ + cp[13] = 0; + if (spec->rsv_key != 0) { + if (spec->rsv_key == prkey->key) { + BDADD8(&cp[12], 1, 0); + BDADD8W(&cp[13], spec->rsv_scope & 0x0f, 7, 4); + BDADD8W(&cp[13], spec->rsv_type & 0x0f, 3, 4); + } + } + /* Reserved */ + DSET32(&cp[14], 0); + /* RELATIVE TARGET PORT IDENTIFIER */ + DSET16(&cp[18], 1 + prkey->pg_idx); + /* ADDITIONAL DESCRIPTOR LENGTH */ + DSET32(&cp[20], 0); + + /* TRANSPORTID */ + plen = snprintf((char *) &cp[24], MAX_INITIATOR_NAME, + "%s", + prkey->registered_initiator_port); + + /* ADDITIONAL DESCRIPTOR LENGTH */ + DSET32(&cp[20], plen); + len += 24 + plen; + } + + total = hlen + len; + /* ADDITIONAL LENGTH */ + DSET32(&data[4], total - hlen); + break; + + default: + ISTGT_ERRLOG("c#%d unsupported service action 0x%x\n", conn->id, sa); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + return total; +} + +static int +istgt_lu_disk_update_reservation(ISTGT_LU_DISK *spec) +{ + int i= 0, rsv_idx = 0; + int ret = 0; + SCSI_PR_DATA *pr_reservation = NULL; + ISTGT_LU_PR_KEY *prkey = NULL; + + if (spec == NULL) + return -1; + int luni = (spec->lu != NULL) ? spec->lu->num : -1; + + /* Lun is in the fake mode, Spurious Reservation commands are not allowed */ + if (spec->fd == -1 || spec->state == ISTGT_LUN_BUSY) { + ret = -1; + ISTGT_ERRLOG("LU%d:RSV-UPD %s (rsvkey?:%lx)", + luni, spec->state == ISTGT_LUN_BUSY ? "FAKE" : "fd invalid", spec->rsv_key); + goto exit; + } + + pr_reservation = xmalloc(sizeof *pr_reservation); + memset(pr_reservation, 0, sizeof *pr_reservation); + + if (spec->npr_keys > MAX_LU_ZAP_RESERVE) { + pr_reservation->npr_keys = MAX_LU_ZAP_RESERVE; + } else { + pr_reservation->npr_keys = spec->npr_keys; + } + pr_reservation->rsv_scope = spec->rsv_scope; + pr_reservation->rsv_type = spec->rsv_type; + pr_reservation->pr_generation = spec->pr_generation; + pr_reservation->rsv_key = spec->rsv_key; + if(spec->rsv_port) + strncpy(pr_reservation->rsv_port, spec->rsv_port, sizeof(pr_reservation->rsv_port) - 1); + pr_reservation->rsv_port[sizeof(pr_reservation->rsv_port) - 1] = '\0'; + for(i = 0; i < spec->npr_keys; i++) { + if(spec->pr_keys[i].key == spec->rsv_key) { + rsv_idx = i; + } + } + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "LU%d:RSV-UPD 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + + /* Update all the npr_keys */ + for (i = 0; i < spec->npr_keys; i++) { + if (i >= MAX_LU_ZAP_RESERVE) { + break; + } + if ((i == MAX_LU_ZAP_RESERVE - 1) && (rsv_idx > MAX_LU_ZAP_RESERVE - 1)) { + prkey = &spec->pr_keys[rsv_idx]; + } else { + prkey = &spec->pr_keys[i]; + } + if (prkey != NULL ) { + /* copy the string */ + pr_reservation->keys[i].key = prkey->key; + strncpy(pr_reservation->keys[i].registered_initiator_port, prkey->registered_initiator_port, + ((strlen(prkey->registered_initiator_port) + 1) > MAX_INITIATOR_NAME ? MAX_INITIATOR_NAME : (strlen(prkey->registered_initiator_port) + 1))); + strncpy(pr_reservation->keys[i].registered_target_port, prkey->registered_target_port, + ((strlen(prkey->registered_target_port) + 1) > MAX_TARGET_NAME ? MAX_TARGET_NAME : (strlen(prkey->registered_target_port) + 1))); + pr_reservation->keys[i].pg_idx= prkey->pg_idx; + pr_reservation->keys[i].pg_tag = prkey->pg_tag; + pr_reservation->keys[i].all_tpg = prkey->all_tpg; + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "LU%d:RSV-UPD.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + } + } + + // TODO Write the Persistent Reservation data to the device as a ZAP attribute + #ifdef __FreeBSD__ + if (ioctl(spec->fd, DIOCGWRRSV, pr_reservation) == -1) { + if (errno != ENOENT){ + ISTGT_ERRLOG("LU%d:RSV-UPD failed:%d (rsvkey:%lx)", + luni, errno, spec->rsv_key); + ret = -1; + } + goto exit; + } + #endif + +exit: + if (pr_reservation) + xfree(pr_reservation); + return ret; + +} + +int +istgt_lu_disk_get_reservation(ISTGT_LU_DISK *spec) +{ + int ret = 0, i = 0, rsv_idx = -1; + SCSI_PR_DATA *pr_reservation = NULL; + SCSI_PR_KEY *prkey = NULL; + if(spec == NULL) + return -1; + int luni = (spec->lu != NULL) ? spec->lu->num : -1; + + pr_reservation = xmalloc(sizeof *pr_reservation); + memset(pr_reservation, 0, sizeof *pr_reservation); + + /* The Lun is in fake mode, Fail here only */ + if (spec->fd == -1) { + ISTGT_NOTICELOG("LU%d:RSV-READ %s (rsvkey?:%lx)", + luni, spec->state == ISTGT_LUN_BUSY ? "FAKE" : "fd invalid", spec->rsv_key); + ret = -1; + spec->rsv_pending |= ISTGT_RSV_READ; + goto exit; + } + + spec->rsv_pending &= ~ISTGT_RSV_READ; + + // TODO Read the Persistent Reservation data from the device + #ifdef __FreeBSD__ + if (ioctl(spec->fd, DIOCGRDRSV, pr_reservation) == -1) { + if (errno != ENOENT) { + ISTGT_ERRLOG("LU%d:RSV-READ failed:%d (rsvkey?:%lx)", + luni, errno, spec->rsv_key); + ret = -1; + spec->rsv_pending |= ISTGT_RSV_READ; + } + goto exit; + } + #endif + + spec->rsv_pending &= ~ISTGT_RSV_READ; + pr_reservation = (SCSI_PR_DATA *)pr_reservation; + + /* Update the spec with the Reservation data */ + if (pr_reservation->npr_keys > MAX_LU_ZAP_RESERVE) { + spec->npr_keys = MAX_LU_ZAP_RESERVE; + } else { + spec->npr_keys = pr_reservation->npr_keys; + } + for(i = 0; i < spec->npr_keys; i++) { + if( pr_reservation->keys[i].key == pr_reservation->rsv_key){ + rsv_idx = i; + } + } + if(rsv_idx == -1) { + spec->npr_keys = 0; + goto exit; + } + spec->rsv_scope = pr_reservation->rsv_scope; + spec->rsv_type = pr_reservation->rsv_type; + spec->pr_generation = pr_reservation->pr_generation; + spec->rsv_key = pr_reservation->rsv_key; + + if (spec->rsv_port != NULL) + xfree(spec->rsv_port); + spec->rsv_port = xstrdup(trim_string(pr_reservation->rsv_port)); + + ISTGT_NOTICELOG("LU%d:RSV-READ 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + + for (i = 0; i < pr_reservation->npr_keys; i++) { + if (i >= MAX_LU_ZAP_RESERVE) { + break; + } + prkey = &pr_reservation->keys[i]; + istgt_lu_disk_free_pr_key(&spec->pr_keys[i]); + if(prkey != NULL) { + spec->pr_keys[i].key = prkey->key; + spec->pr_keys[i].registered_initiator_port = xstrdup(trim_string(prkey->registered_initiator_port)); + spec->pr_keys[i].registered_target_port = xstrdup(trim_string(prkey->registered_target_port)); + spec->pr_keys[i].pg_idx = prkey->pg_idx; + spec->pr_keys[i].pg_tag = prkey->pg_tag; + spec->pr_keys[i].all_tpg = prkey->all_tpg; + ISTGT_NOTICELOG("LU%d:RSV-READ.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d ", + luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag); + } + } + +exit: + if(pr_reservation) + xfree(pr_reservation); + return ret; +} + +int +istgt_lu_disk_copy_reservation(ISTGT_LU_DISK *spec_bkp, ISTGT_LU_DISK *spec) +{ + int i = 0, j = 0; + ISTGT_LU_PR_KEY *prkey_bkp; + ISTGT_LU_PR_KEY *prkey; + + if (spec_bkp->rsv_port != NULL) + xfree(spec_bkp->rsv_port); + + spec_bkp->rsv_port = xstrdup(spec->rsv_port); + spec_bkp->rsv_key = spec->rsv_key; + spec_bkp->spc2_reserved = spec->spc2_reserved; + spec_bkp->rsv_scope = spec->rsv_scope; + spec_bkp->rsv_type = spec->rsv_type; + spec_bkp->pr_generation = spec->pr_generation; + spec_bkp->npr_keys = spec->npr_keys; + + for(i = 0; i < spec->npr_keys;i++) { + prkey = &spec->pr_keys[i]; + prkey_bkp = &spec_bkp->pr_keys[i]; + if(prkey_bkp == NULL) { + prkey = NULL; + continue; + } + istgt_lu_disk_free_pr_key(prkey_bkp); + prkey_bkp->all_tpg = prkey->all_tpg; + prkey_bkp->key = prkey->key; + prkey_bkp->registered_initiator_port + = xstrdup(prkey->registered_initiator_port); + prkey_bkp->registered_target_port + = xstrdup(prkey->registered_target_port); + prkey_bkp->pg_idx = prkey->pg_idx; + prkey_bkp->pg_tag = prkey->pg_tag; + prkey_bkp->ninitiator_ports = prkey->ninitiator_ports; + if(prkey->initiator_ports != NULL) { + prkey_bkp->initiator_ports = xmalloc(sizeof (char *) * MAX_LU_RESERVE_IPT); + memset(prkey_bkp->initiator_ports, 0, sizeof (char *) * MAX_LU_RESERVE_IPT); + for(j =0; j < prkey_bkp->ninitiator_ports; j++) { + if (prkey->initiator_ports[j] == NULL) + continue; + prkey_bkp->initiator_ports[j]= xstrdup(prkey->initiator_ports[j]); + } + } + + } + return 0; +} + + + +int +istgt_lu_disk_print_reservation(ISTGT_LU_Ptr lu, int lun) +{ + int i = 0, j = 0; + ISTGT_LU_PR_KEY *prkey; + ISTGT_LU_DISK *spec; + + if (lu == NULL) + return -1; + if (lun >= lu->maxlun) + return -1; + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + if(spec->persist==0){ + ISTGT_LOG("PERSIST NOT ENABLED, won't read from ZAP"); + return -1; + } + + uint64_t gb_size = spec->size / ISTGT_LU_1GB; + uint64_t mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB; + + ISTGT_NOTICELOG("LU%d:RSV %s %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u %s%s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d inflight:%d\n", + lu->num, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "",spec->xcopy ? " XCOPY" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + lu->lun[lun].rotationrate, + spec->queue_depth, spec->luworkers, spec->luworkersActive, spec->ludsk_ref); + ISTGT_NOTICELOG("LU%d:RSV 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + lu->num, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + ISTGT_NOTICELOG("LU%d:RSV.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + lu->num, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + for (j =0; j < prkey->ninitiator_ports; j++) { + ISTGT_NOTICELOG("LU%d:RSV.%2.2d.%d I:%s", lu->num, i, j, prkey->initiator_ports[j]); + } + } + return 0; +} + +enum prout_sa { + PROUTSA_REGISTER = 0, + PROUTSA_RESERVE, + PROUTSA_RELEASE, + PROUTSA_CLEAR, + PPROUTSA_REEMPT, + PPROUTSA_REEMPT_AND_ABORT, + PROUTSA_REGISTER_AND_IGNORE_EXISTING_KEY, + PROUTSA_REGISTER_AND_MOVE, + PROUTSA_UNK +}; +const char prout_sa[PROUTSA_UNK+2][50] = { + "PROUT_REGISTER", + "PROUT_RESERVE", + "PROUT_RELEASE", + "PROUT_CLEAR", + "PROUT_PREEMPT", + "PROUT_PREEMPT_AND_ABORT", + "PROUT_REGISTER_AND_IGNORE_EXISTING_KEY", + "PROUT_REGISTER_AND_MOVE", + "PROUT_UNK" +}; + +static int +istgt_lu_disk_scsi_persistent_reserve_out(ISTGT_LU_DISK *spec, + CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, + int sa, int scope, int type, uint8_t *data, int len, int spc2) +{ + ISTGT_LU_PR_KEY *prkey; + ISTGT_LU_DISK *spec_bkp = NULL; + char *old_rsv_port = NULL; + char **initiator_ports; + int maxports, nports; + int plen, total; + uint64_t rkey; + uint64_t sarkey; + int bkp_success = 1; + int spec_i_pt, all_tg_pt, aptpl; + int task_abort; + int idx; + int rc; + int ret = 0; + int i; + int change_rsv = 0; + + spec_bkp = xmalloc(sizeof(*spec_bkp)); + memset(spec_bkp, 0, sizeof(*spec_bkp)); + + rkey = DGET64(&data[0]); + sarkey = DGET64(&data[8]); + spec_i_pt = BGET8(&data[20], 3); + all_tg_pt = BGET8(&data[20], 2); + aptpl = BGET8(&data[20], 0); + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + + rc = istgt_lu_disk_copy_reservation(spec_bkp, spec); + if (rc < 0) { + /* Ignore error */ + bkp_success = -1; + } + + switch (sa) { + case 0x00: /* REGISTER */ + change_rsv = 0; + + if (aptpl != 0) { + /* Activate Persist Through Power Loss */ + ISTGT_ERRLOG("c#%d unsupport Activate Persist Through Power Loss\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN PARAMETER LIST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + /* lost reservations if daemon restart */ + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* unregistered port */ + if (rkey != 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + if (sarkey != 0) { + /* XXX check spec_i_pt */ + } + } else { + /* registered port */ + if (spec_i_pt) { + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d Invalid field in CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + prkey = istgt_lu_disk_find_pr_key(spec, + conn->initiator_port, conn->target_port, rkey); + if (prkey == NULL) { + ISTGT_ERRLOG("c#%d key not found initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* not found key */ + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + /* table 33 REGISTER service action in spc3r23 */ + /*if ((spec->rsv_key != 0) && (rkey != 0)) { + if (spec->rsv_key != rkey) { + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + return -1; + } + if (sarkey != 0) + change_rsv = 1; + }*/ + if ((sarkey != 0) && (spec_i_pt == 0)) { + ISTGT_ERRLOG("c#%d change_rsv REGISTER rsvkey:%lx rkey %lx sakey:0x%16.16lx\n", conn->id, spec->rsv_key, rkey, sarkey); + change_rsv = 1; + } + + /* remove existing keys */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + conn->initiator_port, conn->target_port, 0); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + + /* unregister? */ + if (sarkey == 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + goto cleanup_return; + } + + goto do_register; + + case 0x01: /* RESERVE */ + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* unregistered port */ + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, rkey); + if (prkey == NULL) { + /* not found key */ + ISTGT_ERRLOG("c#%d key not found initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + if (spec->rsv_key == 0) { + /* no reservation */ + } else { + if (prkey->key != spec->rsv_key) { + ISTGT_ERRLOG("c#%d prkey->key != spec->rsv_key initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) { + ISTGT_ERRLOG("c#%d spec->rsv_port != conn->initiator_port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + if (g_trace_flag) { + ISTGT_WARNLOG("LU%d: duplicate reserve\n", spec->lu->num); + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + goto cleanup_return; + } + + if (scope != 0x00) { // !LU_SCOPE + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) { + ISTGT_ERRLOG("c#%d unsupported type 0x%x\n", conn->id, type); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* establish reservation by key */ + xfree(spec->rsv_port); + spec->rsv_port = xstrdup(conn->initiator_port); + strlwr(spec->rsv_port); + spec->rsv_key = rkey; + spec->spc2_reserved = 0; + spec->rsv_scope = scope; + spec->rsv_type = type; + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d LU%d: reserved (scope=%d, type=%d) by key=0x%16.16lx\n", + conn->id, spec->lu->num, scope, type, rkey); + break; + + case 0x02: /* RELEASE */ + + if (spec->rsv_key == 0) { + /* no reservation */ + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + goto cleanup_return; + } + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + /* unregistered port */ + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, rkey); + if (prkey == NULL) { + /* not found key */ + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + if (prkey->key != spec->rsv_key) { + /* INVALID RELEASE OF PERSISTENT RESERVATION */ + ISTGT_ERRLOG("c#%d prkey->key != spec->rsv_key initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) { + /* INVALID RELEASE OF PERSISTENT RESERVATION */ + ISTGT_ERRLOG("c#%d spec->rsv_port != conn->initiator_port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + if (scope != 0x00) { // !LU_SCOPE + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) { + ISTGT_ERRLOG("c#%d unsupported type 0x%x\n", conn->id, type); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (spec->rsv_scope != scope || spec->rsv_type != type) { + /* INVALID RELEASE OF PERSISTENT RESERVATION */ + ISTGT_ERRLOG("c#%d spec->rsv_scope != scope || spec->rsv_type != type initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* release reservation by key */ + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->spc2_reserved = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d LU%d: released 0x%16.16lx (scope=%d, type=%d) by key=0x%16.16lx\n", + conn->id, spec->lu->num, spec->rsv_key, scope, type, rkey); + spec->rsv_key = 0; + break; + + case 0x03: /* CLEAR */ + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + /* unregistered port */ + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + + /* release reservation */ + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + + /* remove all registrations */ + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + istgt_lu_disk_free_pr_key(prkey); + } + spec->npr_keys = 0; + break; + + case 0x04: /* PREEMPT */ + + task_abort = 0; + do_preempt: + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + ISTGT_ERRLOG("c#%d unregistered port initiator_port: %s target_port: %s rsv_port: %s\n", conn->id, conn->initiator_port, conn->target_port, spec->rsv_port); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* unregistered port */ + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + ret = -1; + goto cleanup_return; + } + + if (spec->rsv_key == 0) { + /* no reservation */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no reservation\n"); + /* remove registration */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + NULL, NULL, sarkey); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* update generation */ + spec->pr_generation++; + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "rsv_key=0x%16.16"PRIx64"\n", + spec->rsv_key); + + if (spec->rsv_type == ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS + || spec->rsv_type == ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) { + if (sarkey != 0) { + /* remove registration */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + NULL, NULL, sarkey); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* update generation */ + spec->pr_generation++; + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } else { + /* remove other registrations */ + rc = istgt_lu_disk_remove_other_pr_key(spec, conn, + conn->initiator_port, + conn->target_port, + rkey); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_other_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + if (scope != 0x00) { // !LU_SCOPE + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) { + ISTGT_ERRLOG("c#%d unsupported type 0x%x\n", conn->id, type); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* release reservation */ + //xfree(spec->rsv_port); + old_rsv_port = spec->rsv_port; + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + /* establish new reservation */ + spec->rsv_port = xstrdup(conn->initiator_port); + strlwr(spec->rsv_port); + spec->rsv_key = rkey; + spec->rsv_scope = scope; + spec->rsv_type = type; + + ISTGT_NOTICELOG("c#%d LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"PRIx64" rsv:%s (preempt:%s)\n", + conn->id, spec->lu->num, scope, type, rkey, spec->rsv_port, + task_abort && (old_rsv_port != NULL) ? old_rsv_port: "none"); + + /* update generation */ + spec->pr_generation++; + + /* XXX TODO fix */ + if (task_abort) { + /* abort all tasks for preempted I_T nexus */ + if (old_rsv_port != NULL) { + rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port); + xfree(old_rsv_port); + old_rsv_port = NULL; + if (rc < 0) { + /* INTERNAL TARGET FAILURE */ + ISTGT_ERRLOG("c#%d INTERNAL TARGET FAILURE\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + } + if (old_rsv_port != NULL) { + xfree(old_rsv_port); + old_rsv_port = NULL; + } + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + } + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, rkey); + + if (prkey == NULL) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "prkey == NULL\n"); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "prkey key=%16.16"PRIx64"\n", + prkey->key); + } + + if (prkey == NULL + || sarkey != spec->rsv_key) { + if (sarkey != 0) { + /* remove registration */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + NULL, NULL, sarkey); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } else { + /* INVALID FIELD IN PARAMETER LIST */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN PARAMETER LIST\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + + /* remove registration */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + NULL, NULL, sarkey); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + if (scope != 0x00) { // !LU_SCOPE + /* INVALID FIELD IN CDB */ + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY + && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS + && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) { + ISTGT_ERRLOG("c#%d unsupported type 0x%x\n", conn->id, type); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* release reservation */ + //xfree(spec->rsv_port); + old_rsv_port = spec->rsv_port; + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + /* establish new reservation */ + spec->rsv_port = xstrdup(conn->initiator_port); + strlwr(spec->rsv_port); + spec->rsv_key = rkey; + spec->rsv_scope = scope; + spec->rsv_type = type; + + ISTGT_NOTICELOG("c#%d LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"PRIx64" rsv:%s (preempt:%s).\n", + conn->id, spec->lu->num, scope, type, rkey, spec->rsv_port, + task_abort && (old_rsv_port != NULL) ? old_rsv_port: "none"); + + /* update generation */ + spec->pr_generation++; + + /* XXX TODO fix */ + if (task_abort) { + /* abort all tasks for preempted I_T nexus */ + if (old_rsv_port != NULL) { + rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port); + xfree(old_rsv_port); + old_rsv_port = NULL; + if (rc < 0) { + /* INTERNAL TARGET FAILURE */ + ISTGT_ERRLOG("c#%d INTERNAL TARGET FAILURE\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + } + if (old_rsv_port != NULL) { + xfree(old_rsv_port); + old_rsv_port = NULL; + } + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + + case 0x05: /* PREEMPT AND ABORT */ + + task_abort = 1; + goto do_preempt; + + case 0x06: /* REGISTER AND IGNORE EXISTING KEY */ + + if (aptpl != 0) { + /* Activate Persist Through Power Loss */ + ISTGT_ERRLOG("c#%d unsupport Activate Persist Through Power Loss\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN PARAMETER LIST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + /* lost reservations if daemon restart */ + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey == NULL) { + /* unregistered port */ + if (sarkey != 0) { + if (spec_i_pt) { + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + /* unregister? */ + if (sarkey == 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + goto cleanup_return; + } + } else { + /* registered port */ + if (spec_i_pt) { + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + + /* remove existing keys */ + rc = istgt_lu_disk_remove_pr_key(spec, conn, + conn->initiator_port, + conn->target_port, 0); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_remove_pr_key() failed\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* unregister? */ + if (sarkey == 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + goto cleanup_return; + } + + do_register: + /* specified port? */ + nports = 0; + initiator_ports = NULL; + if (spec_i_pt) { + if (len < 28) { + /* INVALID FIELD IN PARAMETER LIST */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN PARAMETER LIST\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + /* TRANSPORTID PARAMETER DATA LENGTH */ + plen = DGET32(&data[24]); + if (28 + plen > len) { + ISTGT_ERRLOG("c#%d invalid length %d (expect %d)\n", + conn->id, len, 28 + plen); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + /* INVALID FIELD IN PARAMETER LIST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "c#%d TransportID parameter data length %d\n", + conn->id, plen); + if (plen != 0) { + maxports = MAX_LU_RESERVE_IPT; + initiator_ports = xmalloc(sizeof (char *) * maxports); + memset(initiator_ports, 0, sizeof (char *) * maxports); + nports = 0; + total = 0; + while (total < plen) { + if (nports >= MAX_LU_RESERVE_IPT) { + ISTGT_ERRLOG("maximum transport IDs\n"); + /* INSUFFICIENT REGISTRATION RESOURCES */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + rc = istgt_lu_parse_transport_id + (&initiator_ports[nports], + &data[24] + total, plen - total); + if (rc < 0) { + /* INVALID FIELD IN PARAMETER LIST */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN PARAMETER LIST\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d got TransportID %s\n", + conn->id, initiator_ports[nports]); + total += rc; + nports++; + } + } + /* check all port unregistered? */ + for (i = 0; i < nports; i++) { + prkey = istgt_lu_disk_find_pr_key(spec, + initiator_ports[i], NULL, 0); + if (prkey != NULL) { + /* registered port */ + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + /* OK, all port unregistered */ + idx = spec->npr_keys; + if (idx + nports >= MAX_LU_RESERVE) { + /* INSUFFICIENT REGISTRATION RESOURCES */ + ISTGT_ERRLOG("c#%d INSUFFICIENT REGISTRATION RESOURCES\n", conn->id); + BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + /* register each I_T nexus */ + for (i = 0; i < nports; i++) { + prkey = &spec->pr_keys[idx + i]; + + /* register new key */ + prkey->key = sarkey; + + /* command received port */ + prkey->registered_initiator_port + = xstrdup(conn->initiator_port); + strlwr(prkey->registered_initiator_port); + prkey->registered_target_port + = xstrdup(conn->target_port); + strlwr(prkey->registered_target_port); + prkey->pg_idx = conn->portal.idx; + prkey->pg_tag = conn->portal.tag; + + /* specified ports */ + prkey->ninitiator_ports = 0; + prkey->initiator_ports = NULL; + prkey->all_tpg = (all_tg_pt) ? 1 : 0; + } + spec->npr_keys = idx + nports; + } + + idx = spec->npr_keys; + if (idx >= MAX_LU_RESERVE) { + /* INSUFFICIENT REGISTRATION RESOURCES */ + ISTGT_ERRLOG("c#%d INSUFFICIENT REGISTRATION RESOURCES\n", conn->id); + BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + prkey = &spec->pr_keys[idx]; + + /* register new key */ + prkey->key = sarkey; + + /* command received port */ + prkey->registered_initiator_port = xstrdup(conn->initiator_port); + strlwr(prkey->registered_initiator_port); + prkey->registered_target_port = xstrdup(conn->target_port); + strlwr(prkey->registered_target_port); + prkey->pg_idx = conn->portal.idx; + prkey->pg_tag = conn->portal.tag; + + /* specified ports */ + prkey->ninitiator_ports = nports; + prkey->initiator_ports = initiator_ports; + prkey->all_tpg = (all_tg_pt) ? 1 : 0; + + if (change_rsv == 1) + { + spec->rsv_key = sarkey; + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d LU%d: reservation (scope=%d, type=%d) changed to " + "by key=0x%16.16"PRIx64"\n", + conn->id, spec->lu->num, scope, type, spec->rsv_key); + } + /* count up keys */ + idx++; + spec->npr_keys = idx; + + /* update generation */ + spec->pr_generation++; + break; + + case 0x07: /* REGISTER AND MOVE */ + /* INVALID FIELD IN CDB */ + ISTGT_ERRLOG("c#%d INVALID FIELD IN CDB\n", conn->id); + ISTGT_LOG("c#%d %s:0x%2.2x key=0x%16.16lx sakey=0x%16.16lx ipt=%d tgpt=%d aptpl=%d iport:%s [0x%16.16lx]\n", + conn->id, prout_sa[(sa > -1 && sa < PROUTSA_UNK) ? sa : PROUTSA_UNK], sa, + rkey, sarkey, spec_i_pt, all_tg_pt, aptpl, conn->initiator_port, spec->rsv_key); + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + + default: + ISTGT_ERRLOG("c#%d unsupported service action 0x%x\n", conn->id, sa); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + /* write reservation to file */ + if(spec->persist && spc2 == 0){ + + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "c#%d Writing Reservations to disk", conn->id); + rc = istgt_lu_disk_update_reservation(spec); + if (rc < 0) { + ISTGT_ERRLOG("c#%d istgt_lu_disk_update_reservation() failed\n", conn->id); + /* Copy only if the backup was successfull */ + if (bkp_success == 1) { + rc = istgt_lu_disk_copy_reservation(spec, spec_bkp); + if (rc < 0) { + ISTGT_ERRLOG("c#%d istgt_lu_disk_copy_reservation() failed\n", conn->id); + } + } + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ret = -1; + goto cleanup_return; + } + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ret = 0; + +cleanup_return: + /* Do a cleanup */ + if (spec_bkp) { + /* remove all registrations */ + for (i = 0; i < spec_bkp->npr_keys; i++) { + prkey = &spec_bkp->pr_keys[i]; + istgt_lu_disk_free_pr_key(prkey); + } + if(spec_bkp->rsv_port) + xfree(spec_bkp->rsv_port); + xfree(spec_bkp); + } + return ret; +} + +int +istgt_lu_disk_check_pr(ISTGT_LU_DISK *spec, CONN_Ptr conn, int pr_allow) +{ + ISTGT_LU_PR_KEY *prkey; + +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "RSV_KEY=0x%16.16"PRIx64", RSV_TYPE=0x%x, PR_ALLOW=0x%x\n", + spec->rsv_key, spec->rsv_type, pr_allow); +#endif /* ISTGT_TRACE_DISK */ + + prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port, + conn->target_port, 0); + if (prkey != NULL) { +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "PRKEY(0x%16.16"PRIx64") found for %s\n", + prkey->key, conn->initiator_port); +#endif /* ISTGT_TRACE_DISK */ + + if (spec->rsv_key == prkey->key) { + /* reservation holder */ + return 0; + } + + switch (spec->rsv_type) { + case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS: + if (pr_allow & PR_ALLOW_ALLRR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS: + if (pr_allow & PR_ALLOW_ALLRR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY: + if (pr_allow & PR_ALLOW_ALLRR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY: + if (pr_allow & PR_ALLOW_ALLRR) + return 0; + return -1; + } + } else { +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "PRKEY not found for %s\n", + conn->initiator_port); +#endif /* ISTGT_TRACE_DISK */ + + switch (spec->rsv_type) { + case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS: + if (pr_allow & PR_ALLOW_WERR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY: + if (pr_allow & PR_ALLOW_WERR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS: + if (pr_allow & PR_ALLOW_EARR) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY: + if (pr_allow & PR_ALLOW_EARR) + return 0; + return -1; + } + } + +#ifdef ISTGT_TRACE_DISK + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "non registrans type\n"); +#endif /* ISTGT_TRACE_DISK */ + /* any I_T nexus */ + switch (spec->rsv_type) { + case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE: + if (pr_allow & PR_ALLOW_WE) + return 0; + return -1; + case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS: + if (pr_allow & PR_ALLOW_EA) + return 0; + return -1; + } + + /* NG */ + return -1; +} + +static int +istgt_lu_disk_scsi_release(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_LU_CMD lu_cmd2; + uint64_t LUI; + uint64_t rkey; + uint8_t cdb[10] = {0}; + uint8_t PRO_data[24] = {0}; + int parameter_len; + int rc; + int luni = (spec->lu != NULL) ? spec->lu->num : -1; + int i = 0; + ISTGT_LU_PR_KEY *prkey = NULL; + + + memset(&lu_cmd2, 0, sizeof lu_cmd2); + //memset(&cdb, 0, sizeof cdb); + lu_cmd2.sense_data = xmalloc(ISTGT_SNSBUFSIZE); + lu_cmd2.sense_alloc_len = ISTGT_SNSBUFSIZE; + lu_cmd2.sense_data_len = 0; + lu_cmd->sense_data_len = 0; + parameter_len = sizeof PRO_data; + + LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU); + rkey = istgt_get_rkey(conn->initiator_name, LUI); + + /* issue release action of PERSISTENT RESERVE OUT */ + cdb[0] = SPC_PERSISTENT_RESERVE_OUT; + BDSET8W(&cdb[1], 0x02, 4, 5); /* RELEASE */ + BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */ + BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */ + cdb[3] = 0; + cdb[4] = 0; + DSET32(&cdb[5], parameter_len); + cdb[9] = 0; + lu_cmd2.cdb = &cdb[0]; + + //memset(&PRO_data, 0, sizeof PRO_data); + DSET64(&PRO_data[0], rkey); // RESERVATION KEY + DSET64(&PRO_data[8], 0); + + rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2, + 0x02, 0x00, 0x03, + PRO_data, parameter_len, 1); + if (rc < 0) { + ISTGT_LOG("c#%d LU%d:RSV-UPD 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + conn->id, luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + if (prkey != NULL ) { + ISTGT_LOG("c#%d LU%d:RSV-UPD.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + conn->id, luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + } + } + lu_cmd->status = lu_cmd2.status; + if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) { + ISTGT_ERRLOG("c#%d Reservation Conflict while releasing initiator_port:%s\n", conn->id, conn->initiator_port); + xfree(lu_cmd2.sense_data); + return -1; + } + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + xfree(lu_cmd2.sense_data); + return -1; + } + + /* issue unregister action of PERSISTENT RESERVE OUT */ + cdb[0] = SPC_PERSISTENT_RESERVE_OUT; + BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */ + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = 0; + DSET32(&cdb[5], parameter_len); + cdb[9] = 0; + lu_cmd2.cdb = &cdb[0]; + + memset(&PRO_data, 0, sizeof PRO_data); + DSET64(&PRO_data[0], rkey); // RESERVATION KEY + DSET64(&PRO_data[8], 0); // unregister + + rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2, + 0x06, 0, 0, + PRO_data, parameter_len, 1); + if (rc < 0) { + ISTGT_LOG("c#%d LU%d:RSV-UPD 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + conn->id, luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + if (prkey != NULL ) { + ISTGT_LOG("c#%d LU%d:RSV-UPD.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + conn->id, luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + } + } + lu_cmd->status = lu_cmd2.status; + if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) { + ISTGT_ERRLOG("c#%d Reservation Conflict while releasing initiator_port:%s\n", conn->id, conn->initiator_port); + xfree(lu_cmd2.sense_data); + return -1; + } + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + xfree(lu_cmd2.sense_data); + return -1; + } + + spec->spc2_reserved = 0; + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + xfree(lu_cmd2.sense_data); + return 0; +} + +#define timediffw(lu_cmd, ch) timediff(lu_cmd, ch, __LINE__) + +#define getdata2(data, lu_cmd) { \ + if (lu_cmd->iobufindx == -1) { \ + data = NULL; \ + ISTGT_ERRLOG("data null\n"); \ + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;\ + return -1; \ + } else { \ + /*?? malloc and copy over all data to data = lu_c*/\ + uint64_t _nb = 0; uint8_t *dptr; int i; \ + for (i = 0; i <= lu_cmd->iobufindx; i++) \ + _nb += lu_cmd->iobuf[i].iov_len; \ + dptr = data = xmalloc(_nb); \ + for (i = 0; i <= lu_cmd->iobufindx; (dptr += lu_cmd->iobuf[i].iov_len), i++) \ + memcpy(dptr, lu_cmd->iobuf[i].iov_base, lu_cmd->iobuf[i].iov_len); \ + freedata = 1; \ + } \ +} +#define getdata(data, lu_cmd) { \ + if (lu_cmd->iobufindx == -1) { \ + data = NULL; \ + ISTGT_ERRLOG("data null\n"); \ + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;\ + break; \ + } else { \ + /*?? malloc and copy over all data to data = lu_c*/\ + uint64_t _nb = 0; uint8_t *dptr; int i; \ + for (i = 0; i <= lu_cmd->iobufindx; i++) \ + _nb += lu_cmd->iobuf[i].iov_len; \ + dptr = data = xmalloc(_nb); \ + for (i = 0; i <= lu_cmd->iobufindx; (dptr += lu_cmd->iobuf[i].iov_len), i++) \ + memcpy(dptr, lu_cmd->iobuf[i].iov_base, lu_cmd->iobuf[i].iov_len); \ + freedata = 1; \ + } \ +} + +static int +istgt_lu_disk_unmap(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data, int pllen) +{ + int markedForFree = 0, diskIoPendingL = 0, lerr = 0; + int len = 8, ret = 0; //actual block starts with offset 8 + off_t unmbd[2]; + int markedForReturn = 0; + uint64_t lba = 0, lblen = 0; + timediffw(lu_cmd, 'w'); + uint64_t maxlba = spec->blockcnt; + while (len + 16 <= pllen) { + unmbd[0] = DGET64(&data[len]); + unmbd[1] = DGET32(&data[len + 8]); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d unmap lba:%lu +%lu blocks (%d/%d)\n", conn->id, unmbd[0], unmbd[1], len, pllen); + if (unmbd[1] != 0) { + lba = unmbd[0]; + lblen = unmbd[1]; + lu_cmd->lba = lba; + lu_cmd->lblen = lblen; + if (lba >= maxlba || lblen > maxlba || lba > (maxlba - lblen)) { + ISTGT_ERRLOG("c#%d end of media in unmap\n", conn->id); + return -1; + } + unmbd[0] *= spec->blocklen; + unmbd[1] *= spec->blocklen; + enterblockingcall(endofmacro1) + if(markedForReturn == 1) + { + ret = -1; + break; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro3) + return -1; + } + + //TODO + #ifdef __FreeBSD__ + ret = ioctl(spec->fd, DIOCGDELETE, unmbd); + #endif + + exitblockingcall(endofmacro2) + if (markedForFree == 1 || markedForReturn == 1) { + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + ret = -1; + break; + } else if (ret == -1) { + lerr = errno; + break; + } + } + len += 16; + } + timediffw(lu_cmd, 'D'); + + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (unmap lba:%lu+%lu)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, lba, lblen); + } else if (ret == -1) { + ISTGT_ERRLOG("c#%d unmap lba:%lu +%lu blocks faild:%d (%d/%d)\n", conn->id, lba, lblen, lerr, len, pllen); + } + return ret; +} + +static int +istgt_lu_disk_scsi_reserve(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_LU_CMD lu_cmd2; + uint64_t LUI; + uint64_t rkey; + uint8_t cdb[10]= {0}; + uint8_t PRO_data[24] = {0}; + int parameter_len; + int rc; + int luni = (spec->lu != NULL) ? spec->lu->num : -1; + int i = 0; + ISTGT_LU_PR_KEY *prkey = NULL; + + memset(&lu_cmd2, 0, sizeof lu_cmd2); + //memset(&cdb, 0, sizeof cdb); + lu_cmd->sense_data_len = 0; + lu_cmd2.sense_data = xmalloc(ISTGT_SNSBUFSIZE); + lu_cmd2.sense_alloc_len = ISTGT_SNSBUFSIZE; + lu_cmd2.sense_data_len = 0; + parameter_len = sizeof PRO_data; + + LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU); + rkey = istgt_get_rkey(conn->initiator_name, LUI); + + /* issue register action of PERSISTENT RESERVE OUT */ + cdb[0] = SPC_PERSISTENT_RESERVE_OUT; + BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */ + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = 0; + DSET32(&cdb[5], parameter_len); + cdb[9] = 0; + lu_cmd2.cdb = &cdb[0]; + + //memset(&PRO_data, 0, sizeof PRO_data); + DSET64(&PRO_data[0], 0); + DSET64(&PRO_data[8], rkey); // SERVICE ACTION RESERVATION KEY + + rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2, + 0x06, 0, 0, + PRO_data, parameter_len, 1); + if (rc < 0) { + ISTGT_LOG("c#%d LU%d:RSV-UPD 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + conn->id, luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + if (prkey != NULL ) { + ISTGT_LOG("c#%d LU%d:RSV-UPD.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + conn->id, luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + } + } + lu_cmd->status = lu_cmd2.status; + if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) { + ISTGT_ERRLOG("c#%d Reservation Conflict while reserving initiator_port:%s\n", conn->id, conn->initiator_port); + xfree(lu_cmd2.sense_data); + return -1; + } + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + xfree(lu_cmd2.sense_data); + return -1; + } + + /* issue reserve action of PERSISTENT RESERVE OUT */ + cdb[0] = SPC_PERSISTENT_RESERVE_OUT; + BDSET8W(&cdb[1], 0x01, 4, 5); /* RESERVE */ + BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */ + BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */ + cdb[3] = 0; + cdb[4] = 0; + DSET32(&cdb[5], parameter_len); + cdb[9] = 0; + lu_cmd2.cdb = &cdb[0]; + + memset(&PRO_data, 0, sizeof PRO_data); + DSET64(&PRO_data[0], rkey); // RESERVATION KEY + DSET64(&PRO_data[8], 0); + + rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2, + 0x01, 0x00, 0x03, + PRO_data, parameter_len, 1); + if (rc < 0) { + ISTGT_LOG("c#%d LU%d:RSV-UPD 0x%16.16lx gen:%d spc2:%d scope:%d type:%d port=[%s] npr:%d", + conn->id, luni, spec->rsv_key, spec->pr_generation, spec->spc2_reserved, + spec->rsv_scope, spec->rsv_type, spec->rsv_port, spec->npr_keys); + for (i = 0; i < spec->npr_keys; i++) { + prkey = &spec->pr_keys[i]; + if (prkey != NULL ) { + ISTGT_LOG("c#%d LU%d:RSV-UPD.%2.2d key:%lx at:%d [I:%s T:%s] idx:%d tag:%d NIN:%d ", + conn->id, luni, i, prkey->key, prkey->all_tpg, prkey->registered_initiator_port, + prkey->registered_target_port, prkey->pg_idx, prkey->pg_tag, + prkey->ninitiator_ports); + } + } + lu_cmd->status = lu_cmd2.status; + if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) { + ISTGT_ERRLOG("c#%d Reservation Conflict while reserving initiator_port:%s\n", conn->id, conn->initiator_port); + xfree(lu_cmd2.sense_data); + return -1; + } + /* INTERNAL TARGET FAILURE */ + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + xfree(lu_cmd2.sense_data); + return -1; + } + + spec->spc2_reserved = 1; + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + xfree(lu_cmd2.sense_data); + return 0; +} +extern void *zv; +static int +istgt_lu_disk_lbread(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len) +{ + uint8_t *data; + uint64_t maxlba; + uint64_t llen; + uint64_t blen; + uint64_t offset; + uint64_t nbytes; + int64_t rc = 0; + int diskIoPendingL = 0, markedForFree = 0; + int markedForReturn = 0; + + if (len == 0) { + lu_cmd->data = NULL; + lu_cmd->data_len = 0; + return 0; + } + + maxlba = spec->blockcnt; + llen = (uint64_t) len; + blen = spec->blocklen; + offset = lba * blen; + nbytes = llen * blen; + + + if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media max:%lu (lba:%lu+%u)\n", conn->id, maxlba, lba, len); + return -1; + } + + data = xmalloc(nbytes); + + if(spec->error_inject & READ_INFLIGHT_ISCSI) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + + enterblockingcall(endofmacro1) + if(markedForReturn == 1) + { + xfree(data); + ISTGT_ERRLOG("Error in locking"); + return -1; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro3) + xfree(data); + return -1; + } + + if(spec->error_inject & READ_INFLIGHT_ONDISK) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + + timediffw(lu_cmd, 'w'); + rc = pread(spec->fd, data, nbytes, offset); + timediffw(lu_cmd, 'D'); + exitblockingcall(endofmacro2) + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (read:%zd/%zd lba:%lu+%u)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nbytes, rc, lba, len); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + xfree(data); + return -1; + } + + if (rc < 0 || (uint64_t) rc != nbytes) { + xfree(data); + errlog(lu_cmd, "c#%d lu_disk_read() failed errnor:%d read:%ld (%lu+%lu, lba:%lu+%u)", conn->id, errno, rc, offset, nbytes, lba, len) + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d Read %"PRId64"/%"PRIu64" bytes (lba:%lu+%u)\n", + conn->id, rc, nbytes, lba, len); + + lu_cmd->data = data; + lu_cmd->data_len = rc; + + return 0; +} + +static int +istgt_lu_disk_lbwrite(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len) +{ + uint64_t maxlba; + uint64_t llen; + uint64_t blen; + uint64_t offset; + uint64_t l_offset = 0; + uint64_t nbytes; + unsigned long nbits = 0; + unsigned long nthbitset = 0; + uint64_t actual; + int64_t rc = 0; + int iovcnt; + struct iovec iov[20]; + int diskIoPendingL = 0, markedForFree = 0; + int markedForReturn = 0; + const char *msg = "write"; + int i; + if (len == 0) { + lu_cmd->data_len = 0; + return 0; + } + + maxlba = spec->blockcnt; + llen = (uint64_t) len; + blen = spec->blocklen; + offset = lba * blen; + nbytes = llen * blen; + + + if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media, max:%lu write lba:%lu+%u\n", conn->id, maxlba, lba, len); + return -1; + } + + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, nbytes); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed (write lba:%lu+%u)\n", conn->id, lba, len); + return -1; + } + + iovcnt = lu_cmd->iobufindx+1; + //memcpy(&iov[0], &lu_cmd->iobuf[0], sizeof(iov)); + for (i=0; iiobuf[i].iov_base; + iov[i].iov_len = lu_cmd->iobuf[i].iov_len; + } + + if (nbytes != lu_cmd->iobufsize) { //aj-the below call doesn't read anything + ISTGT_ERRLOG("c#%d nbytes(%zu) != iobufsize(%zu) (write lba:%lu+%u)\n", + conn->id, (size_t) nbytes, lu_cmd->iobufsize, lba, len); +freeiovcnt: + for (i=0; ilu->readonly) { + ISTGT_ERRLOG("c#%d LU%d: readonly unit\n", conn->id, spec->lu->num); + goto freeiovcnt; + } + if(spec->wzero) { + nbits = nbytes << 3; + nthbitset = find_first_bit(lu_cmd); + } + + if(spec->error_inject & WRITE_INFLIGHT_ISCSI) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + + enterblockingcall(endofmacro1); + if (markedForReturn == 1) { + ISTGT_ERRLOG("c#%d Error in entering block call", conn->id); + goto freeiovcnt; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro3); + goto freeiovcnt; + } + + if(spec->error_inject & WRITE_INFLIGHT_ONDISK) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + + timediffw(lu_cmd, 'w'); + if (spec->wzero && nthbitset == nbits) { + msg = "wzero"; + //TODO + #ifdef __FreeBSD__ + off_t unmbd[2]; + unmbd[0] = offset; + unmbd[1] = nbytes; + rc = ioctl(spec->fd, DIOCGDELETE, unmbd); + if (rc == 0) + rc = nbytes; + #endif + } else { + actual = lu_cmd->iobufsize; l_offset = offset; + while (actual > 0) { + rc = pwritev(spec->fd, &lu_cmd->iobuf[0], iovcnt, l_offset); + if (rc < 0) { + ISTGT_ERRLOG("c#%d pwritev() failed errno:%d\n", conn->id, errno); + break; + } + l_offset += rc; + actual -= rc; + if (actual == 0) + break; + /* adjust iovec length */ + for (i = 0; i < iovcnt; i++) { + if (lu_cmd->iobuf[i].iov_len != 0 && lu_cmd->iobuf[i].iov_len > (size_t)rc) { + lu_cmd->iobuf[i].iov_base = (void *) (((uintptr_t)lu_cmd->iobuf[i].iov_base) + rc); + lu_cmd->iobuf[i].iov_len -= rc; + break; + } else { + rc -= lu_cmd->iobuf[i].iov_len; + lu_cmd->iobuf[i].iov_len = 0; + } + } + } + } + lu_cmd->iobufsize = 0; + lu_cmd->iobufindx = -1; + for (i=0; i< iovcnt; ++i) { + lu_cmd->iobuf[i].iov_base = NULL; + lu_cmd->iobuf[i].iov_len = 0; + } + + exitblockingcall(endofmacro2) + timediffw(lu_cmd, 'D'); + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_ERRLOG("c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (wrote:%zd/%zd lba:%lu+%u)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nbytes, rc, lba, len); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + for (i=0; iid, rc, offset, nbytes, l_offset, lba, len) + for (i=0; iid, rc, nbytes, lba, len, msg); + + lu_cmd->data_len = rc; + for (i=0; iblockcnt; + llen = (uint64_t) len; + const char *msg = "wsame"; + if (llen == 0) { + if (lba >= maxlba) { + ISTGT_ERRLOG("end of media\n"); + return -1; + } + llen = maxlba - lba; + } + blen = spec->blocklen; + offset = lba * blen; + nbytes = 1 * blen; + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d Write Same: max=%"PRIu64", lba=%"PRIu64", len=%u\n", + conn->id, maxlba, lba, len); + + if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) { + ISTGT_ERRLOG("end of media\n"); + return -1; + } + + + if (spec->lu->readonly) { + ISTGT_ERRLOG("c#%d LU%d: readonly unit\n", conn->id, spec->lu->num); + return -1; + } + getdata2(data, lu_cmd) + + if (spec->wzero) { + nbits = nbytes << 3; + nthbitset = find_first_bit(lu_cmd); + } + if (spec->wzero && nthbitset == nbits) { + msg = "wzero"; + enterblockingcall(endofmacro1); + if(markedForReturn == 1) + { + if(freedata == 1) + xfree(data); + ISTGT_ERRLOG("c#%d Error in locking", conn->id); + return -1; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro5) + if(freedata == 1) + xfree(data); + return -1; + } + //TODO + #ifdef __FreeBSD__ + off_t unmbd[2]; + unmbd[0] = offset; + unmbd[1] = llen * blen; + rc = ioctl(spec->fd, DIOCGDELETE, unmbd); + #endif + eno = errno; + exitblockingcall(endofmacro2); + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (wsameX lba:%lu+%u ret:%ld).", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, lba, len, rc); + if(freedata == 1) + xfree(data); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + return -1; + } + if (rc == -1) { + if(freedata == 1) + xfree(data); + ISTGT_ERRLOG("c#%d wsameX lba:%lu+%u failed %ld/%d\n", conn->id, lba, len, rc, eno); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d wzero_same done lba:%lu+%u\n", conn->id, lba, len); + + if(freedata == 1) + xfree(data); + lu_cmd->data_len = nbytes; + return 0; + } + + wblocks = (int64_t)worksize / nbytes; + if (wblocks == 0) { + ISTGT_ERRLOG("c#%d work buffer is too small\n", conn->id); + if (freedata == 1) xfree(data); + return -1; + } + + nblocks = 0; + workbuf = xmalloc(worksize); + while (nblocks < wblocks) { + memcpy(workbuf + (nblocks * nbytes), data, nbytes); + nblocks++; + } + nblocks = 0; + offset_local = offset; + timediffw(lu_cmd, 'w'); + while (nblocks < llen) { + uint64_t reqblocks = DMIN64(wblocks, (llen - nblocks)); + uint64_t reqbytes = reqblocks * nbytes; + enterblockingcall(endofmacro3); + if(markedForReturn == 1) + { + if(freedata == 1) + xfree(data); + xfree(workbuf); + ISTGT_ERRLOG("c#%d Error in locking", conn->id); + return -1; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro6) + if(freedata == 1) + xfree(data); + xfree(workbuf); + return -1; + } + rc = pwrite(spec->fd, workbuf, reqbytes, offset_local); + exitblockingcall(endofmacro4); + if (markedForFree == 1 || markedForReturn == 1) { + timediffw(lu_cmd, 'D'); + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (wrote:%zd of %zd. ret:%zd).", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nblocks, llen, rc); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + if (freedata == 1) xfree(data); + xfree(workbuf); + return -1; + } + if (rc < 0 || (uint64_t) rc != reqbytes) { + timediffw(lu_cmd, 'D'); + errlog(lu_cmd, "c#%d lu_disk_write() failed wrote:%lu, %lu of %lu blksize, blksz:%zd", conn->id, rc, nblocks, llen, nbytes) + if (freedata == 1) xfree(data); + xfree(workbuf); + return -1; + } + offset_local += reqbytes; + nblocks += reqblocks; + } + + timediffw(lu_cmd, 'D'); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d Wrote %"PRId64" at %"PRIu64" bytes %s\n", + conn->id, (llen * nbytes), offset, msg); + + lu_cmd->data_len = nbytes; + + if (freedata == 1) xfree(data); + xfree(workbuf); + return 0; +} + +static int +istgt_lu_disk_lbwrite_ats(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len) +{ + uint8_t *data = NULL; + uint8_t *watsbuf; + uint64_t maxlba; + uint64_t llen; + uint64_t blen; + uint64_t offset; + uint64_t nbytes; + int64_t rc; + int diskIoPendingL = 0, markedForFree = 0; + int markedForReturn = 0; + int freedata = 0; + if (len == 0) { + lu_cmd->data_len = 0; + return 0; + } + + maxlba = spec->blockcnt; + llen = (uint64_t) len; + blen = spec->blocklen; + offset = lba * blen; + nbytes = llen * blen; + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d Write ATS: max=%"PRIu64", lba=%"PRIu64", len=%u\n", + conn->id, maxlba, lba, len); + + if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media\n", conn->id); + return -1; + } + + if (spec->lu->readonly) { + ISTGT_ERRLOG("c#%d LU%d: readonly unit\n", conn->id, spec->lu->num); + return -1; + } + + getdata2(data, lu_cmd) + + /* start atomic test and set */ + + watsbuf = xmalloc(nbytes); + enterblockingcall(endofmacro1) + if(markedForReturn == 1) + { + ISTGT_ERRLOG("c#%d Error in locking", conn->id); + return -1; + } + timediffw(lu_cmd, 'w'); + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro5) + if(freedata == 1) + xfree(data); + xfree(watsbuf); + return -1; + } + rc = pread(spec->fd, watsbuf, nbytes, offset); + exitblockingcall(endofmacro2) + if (markedForFree == 1 || markedForReturn == 1) { + timediffw(lu_cmd, 'D'); + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (ats read:%zd/%zd @%zd)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nbytes, rc, offset); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + if (freedata == 1) xfree(data); + xfree(watsbuf); + return -1; + } + if (rc < 0 || (uint64_t) rc != nbytes) { + timediffw(lu_cmd, 'D'); + errlog(lu_cmd, "c#%d lu_disk_read()ats failed %ld/%lu\n", conn->id, rc, nbytes) + xfree(watsbuf); + if (freedata == 1) xfree(data); + return -1; + } + +#if 0 + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS VERIFY", data, nbytes); + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS WRITE", data + nbytes, nbytes); + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS DATA", spec->watsbuf, nbytes); +#endif + if (memcmp(watsbuf, data, nbytes) != 0) { + timediffw(lu_cmd, 'D'); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"c#%d ATS: Miscompare %s\n", conn->id, spec->file); + /* MISCOMPARE DURING VERIFY OPERATION */ + BUILD_SENSE(MISCOMPARE, 0x1d, 0x00); + xfree(watsbuf); + if (freedata == 1) xfree(data); + return -1; + } + + enterblockingcall(endofmacro3) + if(markedForReturn == 1) + { + if(freedata == 1) + xfree(data); + xfree(watsbuf); + ISTGT_ERRLOG("c#%d Error in locking", conn->id); + return -1; + } + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro6) + if(freedata == 1) + xfree(data); + xfree(watsbuf); + return -1; + } + rc = pwrite(spec->fd, data + nbytes, nbytes, offset); + exitblockingcall(endofmacro4) + timediffw(lu_cmd, 'D'); + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (ats write:%zd/%zd @%zd)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nbytes, rc, offset); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + xfree(watsbuf); + if (freedata == 1) xfree(data); + return -1; + } + if (rc < 0 || (uint64_t) rc != nbytes) { + errlog(lu_cmd, "c#%d lu_disk_write()ats failed %ld/%lu errno:%d\n", conn->id, rc, nbytes, errno) + xfree(watsbuf); + if (freedata == 1) xfree(data); + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d Wrote %"PRId64"/%"PRIu64" bytes\n", + conn->id, rc, nbytes); + + /* end atomic test and set */ + + lu_cmd->data_len = nbytes * 2; + xfree(watsbuf); + if (freedata == 1) xfree(data); + return 0; +} + +static int +istgt_lu_disk_lbsync(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd __attribute__((__unused__)), uint64_t lba, uint32_t len) +{ + uint64_t maxlba; + uint64_t llen; + uint64_t blen; + uint64_t offset; + uint64_t nbytes; + int64_t rc; + int diskIoPendingL = 0, markedForFree = 0; + int markedForReturn = 0; + + if (len == 0) { + return 0; + } + + maxlba = spec->blockcnt; + llen = (uint64_t) len; + blen = spec->blocklen; + offset = lba * blen; + nbytes = llen * blen; + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n", + conn->id, maxlba, lba, len); + + if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media\n", conn->id); + return -1; + } + + enterblockingcall(endofmacro1) + if(markedForReturn == 1) + { + ISTGT_ERRLOG("c#%d Error in locking", conn->id); + return -1; + } + timediffw(lu_cmd, 'w'); + if(lu_cmd->aborted == 1) + { + ISTGT_LOG("(0x%x) c#%d aborting the IO\n", lu_cmd->CmdSN, conn->id); + exitblockingcall(endofmacro3) + return -1; + } + rc = spec->sync(spec, offset, nbytes); + exitblockingcall(endofmacro2) + timediffw(lu_cmd, 'D'); + if (markedForFree == 1 || markedForReturn == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_NET, "c#%d connGone(%d)OrMarkedReturn(%d):%p:%d pendingIO:%d (sync:%zd/%zd @%zd)", + conn->id, markedForFree, markedForReturn, conn, conn->cid, diskIoPendingL, nbytes, rc, offset); + if (diskIoPendingL == 0 && markedForFree == 1) + lu_cmd->connGone = 1; + return -1; + } + if (rc < 0) { + errlog(lu_cmd, "c#%d lu_disk_sync() failed %ld %lu-%lu\n", conn->id, rc, offset, nbytes) + return -1; + } + + return 0; +} + +void +istgt_lu_scsi_build_sense_data(ISTGT_LU_CMD_Ptr lu_cmd, int sk, int asc, int ascq) +{ + uint8_t *cp; + int resp_code; + int hlen = 0, len = 0, plen; + int total; + uint8_t *data = lu_cmd->sense_data = xmalloc(200); + + resp_code = 0x70; /* Current + Fixed format */ + + /* SenseLength */ + DSET16(&data[0], 0); + hlen = 2; + + /* Sense Data */ + cp = &data[hlen + len]; + + /* VALID(7) RESPONSE CODE(6-0) */ + BDSET8(&cp[0], 1, 7); + BDADD8W(&cp[0], resp_code, 6, 7); + /* Obsolete */ + cp[1] = 0; + /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ + BDSET8W(&cp[2], sk, 3, 4); + /* INFORMATION */ + cp[3] = 0; cp[4] = 0; cp[5] = 0; cp[6] = 0; //memset(&cp[3], 0, 4); + /* ADDITIONAL SENSE LENGTH */ + cp[7] = 0; + len = 8; + + /* COMMAND-SPECIFIC INFORMATION */ + cp[8] = 0; cp[9] = 0; cp[10] = 0; cp[11] = 0; //memset(&cp[8], 0, 4); + /* ADDITIONAL SENSE CODE */ + cp[12] = asc; + /* ADDITIONAL SENSE CODE QUALIFIER */ + cp[13] = ascq; + /* FIELD REPLACEABLE UNIT CODE */ + cp[14] = 0; + /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ + cp[15] = 0; + cp[16] = 0; + cp[17] = 0; + /* Additional sense bytes */ + //data[18] = 0; + plen = 18 - len; + + /* ADDITIONAL SENSE LENGTH */ + cp[7] = plen; + + total = hlen + len + plen; + + /* SenseLength */ + DSET16(&data[0], total - 2); + + lu_cmd->sense_data_len = total; + return; +} + +void +istgt_lu_scsi_build_sense_data2(ISTGT_LU_CMD_Ptr lu_cmd, int sk, int asc, int ascq) +{ + uint8_t *cp; + int resp_code; + int hlen = 0, len = 0, plen; + int total; + uint8_t *data = lu_cmd->sense_data = xmalloc(200); + + resp_code = 0x71; /* Deferred + Fixed format */ + + /* SenseLength */ + DSET16(&data[0], 0); + hlen = 2; + + /* Sense Data */ + cp = &data[hlen + len]; + + /* VALID(7) RESPONSE CODE(6-0) */ + BDSET8(&cp[0], 1, 7); + BDADD8W(&cp[0], resp_code, 6, 7); + /* Obsolete */ + cp[1] = 0; + /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ + BDSET8W(&cp[2], sk, 3, 4); + /* INFORMATION */ + cp[3] = 0; cp[4] = 0; cp[5] = 0; cp[6] = 0; //memset(&cp[3], 0, 4); + /* ADDITIONAL SENSE LENGTH */ + cp[7] = 0; + len = 8; + + /* COMMAND-SPECIFIC INFORMATION */ + cp[8] = 0; cp[9] = 0; cp[10] = 0; cp[11] = 0; //memset(&cp[8], 0, 4); + /* ADDITIONAL SENSE CODE */ + cp[12] = asc; + /* ADDITIONAL SENSE CODE QUALIFIER */ + cp[13] = ascq; + /* FIELD REPLACEABLE UNIT CODE */ + cp[14] = 0; + /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ + cp[15] = 0; + cp[16] = 0; + cp[17] = 0; + /* Additional sense bytes */ + //data[18] = 0; + plen = 18 - len; + + /* ADDITIONAL SENSE LENGTH */ + cp[7] = plen; + + total = hlen + len + plen; + + /* SenseLength */ + DSET16(&data[0], total - 2); + + lu_cmd->sense_data_len = total; + return; +} + + +IT_NEXUS * +istgt_lu_disk_get_nexus(ISTGT_LU_DISK *spec, const char *initiator_port) +{ + IT_NEXUS *nexus; + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + if (strcasecmp(nexus->initiator_port, initiator_port) == 0) + return (nexus); + } + return NULL; +} + +int +istgt_lu_disk_build_ua(istgt_ua_type ua_pending, int *sk, int *asc, int *ascq) +{ + istgt_ua_type ua_to_build = ISTGT_UA_NONE; + uint64_t i; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_build_ua\n"); + + if (ua_pending == ISTGT_UA_NONE) + return(ua_pending); + + for (i =0 ; i < (sizeof(ua_pending)* 8); i++) { + if (ua_pending & (1 << i)) { + ua_to_build = 1 << i; + break; + } + } + + *sk = ISTGT_SCSI_SENSE_UNIT_ATTENTION; + + switch (ua_to_build) { + case ISTGT_UA_POWERON: + /* 29h/01h POWER ON OCCURRED */ + *asc = 0x29; + *ascq = 0x01; + break; + case ISTGT_UA_BUS_RESET: + /* 29h/02h SCSI BUS RESET OCCURRED */ + *asc = 0x29; + *ascq = 0x02; + break; + case ISTGT_UA_TARG_RESET: + /* 29h/03h BUS DEVICE RESET FUNCTION OCCURRED*/ + *asc = 0x29; + *ascq = 0x03; + break; + case ISTGT_UA_LUN_RESET: + /* 29h/00h POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */ + /* + * Since we don't have a specific ASC/ASCQ pair for a LUN + * reset, just return the generic reset code. + */ + *asc = 0x29; + *ascq = 0x00; + break; + case ISTGT_UA_LUN_CHANGE: + /* 3Fh/0Eh REPORTED LUNS DATA HAS CHANGED */ + *asc = 0x3F; + *ascq = 0x0E; + break; + case ISTGT_UA_MODE_CHANGE: + /* 2Ah/01h MODE PARAMETERS CHANGED */ + *asc = 0x2A; + *ascq = 0x01; + break; + case ISTGT_UA_LOG_CHANGE: + /* 2Ah/02h LOG PARAMETERS CHANGED */ + *asc = 0x2A; + *ascq = 0x02; + break; + case ISTGT_UA_LVD: + /* 29h/06h TRANSCEIVER MODE CHANGED TO LVD */ + *asc = 0x29; + *ascq = 0x06; + break; + case ISTGT_UA_SE: + /* 29h/05h TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */ + *asc = 0x29; + *ascq = 0x05; + break; + case ISTGT_UA_RES_PREEMPT: + /* 2Ah/03h RESERVATIONS PREEMPTED */ + *asc = 0x2A; + *ascq = 0x03; + break; + case ISTGT_UA_RES_RELEASE: + /* 2Ah/04h RESERVATIONS RELEASED */ + *asc = 0x2A; + *ascq = 0x04; + break; + case ISTGT_UA_REG_PREEMPT: + /* 2Ah/05h REGISTRATIONS PREEMPTED */ + *asc = 0x2A; + *ascq = 0x05; + break; + case ISTGT_UA_ASYM_ACC_CHANGE: + /* 2Ah/06n ASYMMETRIC ACCESS STATE CHANGED */ + *asc = 0x2A; + *ascq = 0x06; + break; + case ISTGT_UA_CAPACITY_CHANGED: + /* 2Ah/09n CAPACITY DATA HAS CHANGED */ + *asc = 0x2A; + *ascq = 0x09; + break; + default: + ua_to_build = ISTGT_UA_NONE; + return (ua_to_build); + break; /* NOTREACHED */ + } + + return ua_to_build; +} + +int +istgt_lu_disk_persist_reservation(ISTGT_LU_Ptr lu, int lun, char* arg) +{ + ISTGT_LU_DISK *spec; + + if (lu == NULL) { + ISTGT_LOG("lu is NULL"); + return -1; + } + if (lun >= lu->maxlun) { + ISTGT_LOG("lu %d > max %d", lun, lu->maxlun); + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + ISTGT_LOG("lu %d type %d", lun, lu->lun[lun].type); + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_LOG("lu1 %d type %d", lun, lu->lun[lun].type); + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if(*arg == '1') + spec->persist = 1; + else + spec->persist = 0; + return 0; +} + +int +istgt_lu_disk_sync_reservation(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec; + int rc; + int ret; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + + if(spec->persist==0){ + ISTGT_LOG("SYNCing even with PERSIST DISABLED"); + } + + MTX_LOCK(&spec->pr_rsv_mutex); + /* write reservation to file */ + ISTGT_LOG("Syncing Reservation"); + rc = istgt_lu_disk_update_reservation(spec); + if (rc < 0) { + ISTGT_ERRLOG("istgt_lu_disk_update_reservation() failed\n"); + } + + ret = 0; + MTX_UNLOCK(&spec->pr_rsv_mutex); + + return ret; + +} + + + + + +int +istgt_lu_disk_reset(ISTGT_LU_Ptr lu, int lun , istgt_ua_type ua_type) +{ + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + int rc, cleared = 0; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + + #if 0 + if (spec->lock) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n"); + spec->lock = 0; + } + #endif + + /* Abort alll the commands in the queue */ + if (lu->queue_depth != 0) { + cleared = istgt_lu_disk_queue_clear_all(lu, lun); + if (cleared < 0) { + ISTGT_ERRLOG("lu_disk_queue_clear_all() failed\n"); + return -1; + } + } + + /* re-open file */ + if (!spec->lu->readonly) { + rc = spec->sync(spec, 0, spec->size); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_sync() failed\n", + lu->num, lun); + /* ignore error */ + } + } + + /* SAM-3 (SCSI ARCHITECTURE MODEL): + * Before returning a FUNCTION COMPLETE response, the target port + * shall perform logical unit reset functions specified in spec. + + * Relase all the Reservation Established using RESERVE/RELEASE + * Management methods (Persistant Reservation shall not be altered). + + * A unit_attention (UA) condition for all initiators that have + * access shall be created on each of these logical units. + */ + + istgt_lu_disk_seek_raw(spec, 0); + + if (spec->spc2_reserved) { + /* release reservation by key */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"LU%d: Lun Reset cleared the SPC2 reservations \n", lu->num); + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->spc2_reserved = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + } + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Set U/A to all the initiator that have access to LU%d \n", lu->num); + TAILQ_FOREACH(nexus, &spec->nexus, nexus_next) { + if (nexus == NULL) + break; + nexus->ua_pending |= ua_type; + } + return cleared; +} + +int +istgt_lu_disk_clear_reservation(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec, *spec_bkp; + int i; + int bkp_success = 1; + int rc; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + spec_bkp = xmalloc(sizeof(*spec_bkp)); + memset(spec_bkp, 0, sizeof(*spec_bkp)); + + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_copy_reservation(spec_bkp, spec); + if (rc < 0) { + /* Ignore error */ + bkp_success = -1; + MTX_UNLOCK(&spec->pr_rsv_mutex); + xfree(spec_bkp); + return rc; + } + /* release reservation */ + xfree(spec->rsv_port); + spec->rsv_port = NULL; + spec->rsv_key = 0; + spec->rsv_scope = 0; + spec->rsv_type = 0; + + /* remove all registrations */ + for (i = 0; i < spec->npr_keys; i++) { + istgt_lu_disk_free_pr_key(&spec->pr_keys[i]); + } + spec->npr_keys = 0; + for (i = 0; i < MAX_LU_RESERVE; i++) { + memset(&spec->pr_keys[i], 0, sizeof(spec->pr_keys[i])); + } + if(spec->persist && spec->spc2_reserved == 0){ + rc = istgt_lu_disk_update_reservation(spec); + if (rc < 0) { + ISTGT_ERRLOG("istgt_lu_disk_update_reservation() failed\n"); + /* Copy only if the backup was successfull */ + if (bkp_success == 1) { + rc = istgt_lu_disk_copy_reservation(spec, spec_bkp); + if (rc < 0) { + ISTGT_LOG("istgt_lu_disk_copy_reservation() failed\n"); + } + } + } + } + spec->spc2_reserved = 0; + MTX_UNLOCK(&spec->pr_rsv_mutex); + xfree(spec_bkp); + return rc; +} + +int +istgt_lu_disk_start(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec; + int flags; + int rc; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + + flags = lu->readonly ? O_RDONLY : O_RDWR; + if(spec->fd > -1) { + ISTGT_ERRLOG("LU%d: LUN%d:istgt_lu_disk_start() failed, Device is already open\n", + lu->num, lun); + return -1; + } + rc = spec->open(spec, flags, 0666); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_open() failed\n", + lu->num, lun); + return -1; + } + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_ONLINE; + spec->ex_state = ISTGT_LUN_OPEN; + MTX_UNLOCK(&spec->state_mutex); + lu->limit_q_size=0; + + /* Online the logical unit */ + lu->online = 1; + + return 0; +} + +int +istgt_lu_disk_stop(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec; + CONN_Ptr conn; + int rc; + int j; + int workers_signaled = 0, loop = 0; + struct timespec _s1, _s2, _s3, _wrk, _wrkx; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + clock_gettime(clockid, &_wrk); + if (lu->queue_depth != 0) { + rc = istgt_lu_disk_queue_clear_all(lu, lun); + if (rc < 0) { + ISTGT_ERRLOG("lu_disk_queue_clear_all() failed\n"); + return -1; + } + } + + for (j = 1; j < MAX_LU_TSIH; j++) { + if (lu->tsih[j].initiator_port != NULL + && lu->tsih[j].tsih != 0) { + /* Find conn */ + conn = istgt_find_conn(lu->tsih[j].initiator_port, lu->name, lu->tsih[j].tsih); + if (conn == NULL) + continue; + /* Send asyn notification to the client */ + istgt_iscsi_send_async(conn); + } + } + + /* Offline the Logical Unit + * Complete Logical Unit Need not be offlined if we have to stop a particular LUN. + * CloudByte Supports/Configures one LUN per Logical Unit so making complete LU to be offline. + */ + lu->online = 0; + timesdiff(_wrk, _wrkx, _s1) + do { + MTX_LOCK(&spec->state_mutex); + spec->state = ISTGT_LUN_BUSY; + if (spec->ludsk_ref == 0) + workers_signaled = 1; + spec->ex_state = ISTGT_LUN_CLOSE_INPROGRESS; + MTX_UNLOCK(&spec->state_mutex); + if (workers_signaled == 0) + sleep(1); + } while ((workers_signaled == 0) && (++loop < 10)); + timesdiff(_wrkx, _wrk, _s2) + + /* re-open file */ + if (!spec->lu->readonly) { + rc = spec->sync(spec, 0, spec->size); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_sync() failed\n", + lu->num, lun); + lu->online = 1; + return -1; + } + } + rc = spec->close(spec); + timesdiff(_wrk, _wrkx, _s3) + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_close() failed\n", + lu->num, lun); + lu->online = 1; + return -1; + } + MTX_LOCK(&spec->state_mutex); + spec->ex_state = ISTGT_LUN_CLOSE; + MTX_UNLOCK(&spec->state_mutex); + ISTGT_LOG("LU%d: LUN%d %s: storage_stop [%ld.%ld - %ld.%ld - %ld.%ld]\n", + lu->num, lun, lu->name ? lu->name : "-", + _s1.tv_sec, _s1.tv_nsec, _s2.tv_sec, _s2.tv_nsec, _s3.tv_sec, _s3.tv_nsec); + + return 0; +} + + +int +istgt_lu_disk_modify(ISTGT *istgt, int dofake) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_DISK *spec; + int i, j; + int rc; + int failsignal = 0; + const istgt_action act = dofake ? ACTION_CLOSE : ACTION_OPEN; + const char *mode = dofake ? "fake" : "real"; + struct timespec st, wrk, wrkx, dif1, dif2; + const istgt_lun_ex_state expstate1 = dofake ? ISTGT_LUN_CLOSE_PENDING : ISTGT_LUN_OPEN_PENDING; + const istgt_lun_ex_state expstate2 = dofake ? ISTGT_LUN_CLOSE_INPROGRESS : ISTGT_LUN_OPEN_INPROGRESS; + int notyet = 0, signaled = 0, skipped = 0, loopCnt = 0; + + ISTGT_LOG("istgtcontrol modify %s starting\n", mode); + clock_gettime(clockid, &st); + + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + for (j = 0; j < lu->maxlun; j++) { + spec = (ISTGT_LU_DISK *) lu->lun[j].spec; + if (spec == NULL) + continue; + spec->dofake = dofake; + rc = istgt_lu_disk_signal_action(lu, j, &st, act); //rc = istgt_lu_disk_update_raw(lu, j, dofake); + if (rc < 0) + ++failsignal; + else if (rc == 1) + ++signaled; + else + ++skipped; + } + } + timesdiff(st,wrk,dif1) + + notyet = signaled; + + while ((notyet > 0) && (++loopCnt < 180)) { + sleep(1); + for (notyet = 0, i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + for (j = 0; j < lu->maxlun; j++) { + spec = (ISTGT_LU_DISK *) lu->lun[j].spec; + if (spec == NULL) + continue; + if (spec->ex_state == expstate1 || spec->ex_state == expstate2) + ++notyet; + } + } + } + timesdiff(wrk,wrkx,dif2) + ISTGT_LOG("istgtcontrol modify %s done signaled:%d notdone:%d [%ld.%ld - %ld.%ld]\n", + mode, signaled, notyet, dif1.tv_sec, dif1.tv_nsec, dif2.tv_sec, dif2.tv_nsec); + return (failsignal || notyet) ? -1 : 0; +} + + +int +istgt_lu_disk_status(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec; + int status; + + if (lu == NULL) { + return -1; + } + if (lun >= lu->maxlun) { + return -1; + } + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + + MTX_LOCK(&spec->state_mutex); + status = spec->state; + MTX_UNLOCK(&spec->state_mutex); + + return (status); +} + +static int +istgt_lu_disk_queue_clear_internal(CONN_Ptr conn, ISTGT_LU_DISK *spec, const char *initiator_port, int all_cmds, uint32_t CmdSN) +{ + ISTGT_QUEUE_Ptr r_ptr; + ISTGT_LU_TASK_Ptr lu_task, tptr; + void *cookie; + ISTGT_LU_CMD_Ptr lu_cmd; + ISTGT_QUEUE saved_queue; + ISTGT_QUEUE saved_bqueue; + ISTGT_QUEUE saved_queue1; + ISTGT_QUEUE saved_bqueue1; + int need_signal = 0; + struct timespec now; + int rc = 0; + int k; + char buf[2048]; + char *bp = buf; + int rem = 2040, ln, i, used; + char c; + int cleared = 0; + int ilen = initiator_port ? strlen(initiator_port) : 0; + struct timespec abstime; + time_t now_wait; + int already_waited = 0; + memset(&abstime, 0, sizeof abstime); + + if (spec == NULL) + return -1; + + if (all_cmds != 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s\n", + initiator_port); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s, CmdSN=0x%x\n", + initiator_port, CmdSN); + } + + istgt_queue_init(&saved_queue); + istgt_queue_init(&saved_bqueue); + istgt_queue_init(&saved_queue1); + istgt_queue_init(&saved_bqueue1); + + clock_gettime(clockid, &now); //now = time(NULL); + MTX_LOCK(&spec->complete_queue_mutex); + while (1) { + lu_task = istgt_queue_dequeue(&spec->cmd_queue); + if (lu_task == NULL) + break; + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + //Return Release Aborted, but not actually aborting it. Just the response won't be sent + if((abort_release == 1) && ((lu_task->lu_cmd.cdb[0] == SPC2_RELEASE_6) || (lu_task->lu_cmd.cdb[0] == SPC2_RELEASE_10))) { + lu_task->lu_cmd.release_aborted = 1; + cleared++; + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu Release cleared from cmdq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + goto saved_cmd_queue; + } + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared from cmdq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + goto error_return; + } + cleared++; + need_signal = 1; + continue; + } +saved_cmd_queue: + r_ptr = istgt_queue_enqueue(&saved_queue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + while (1) { + lu_task = istgt_queue_dequeue(&saved_queue); + if (lu_task == NULL) + break; + r_ptr = istgt_queue_enqueue(&spec->cmd_queue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + + while (1) { + lu_task = istgt_queue_dequeue(&spec->blocked_queue); + if (lu_task == NULL) + break; + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + if((abort_release == 1) && ((lu_task->lu_cmd.cdb[0] == SPC2_RELEASE_6) || (lu_task->lu_cmd.cdb[0] == SPC2_RELEASE_10))) { + lu_task->lu_cmd.release_aborted = 1; + cleared++; + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu Release cleared from blockedq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + goto saved_blocked_queue; + } + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared from blockedq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + goto error_return; + } + cleared++; + need_signal = 1; + continue; + } +saved_blocked_queue: + r_ptr = istgt_queue_enqueue(&saved_bqueue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + while (1) { + lu_task = istgt_queue_dequeue(&saved_bqueue); + if (lu_task == NULL) + break; + r_ptr = istgt_queue_enqueue(&spec->blocked_queue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + + need_signal = 0; + + while (1) { + lu_task = istgt_queue_dequeue(&spec->maint_cmd_queue); + if (lu_task == NULL) + break; + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared from maintcmdq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + goto error_return; + } + cleared++; + need_signal = 1; + continue; + } + r_ptr = istgt_queue_enqueue(&saved_queue1, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + while (1) { + lu_task = istgt_queue_dequeue(&saved_queue1); + if (lu_task == NULL) + break; + r_ptr = istgt_queue_enqueue(&spec->maint_cmd_queue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + + while (1) { + lu_task = istgt_queue_dequeue(&spec->maint_blocked_queue); + if (lu_task == NULL) + break; + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared from maintblkdq\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + goto error_return; + } + cleared++; + need_signal = 1; + continue; + } + r_ptr = istgt_queue_enqueue(&saved_bqueue1, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + while (1) { + lu_task = istgt_queue_dequeue(&saved_bqueue1); + if (lu_task == NULL) + break; + r_ptr = istgt_queue_enqueue(&spec->maint_blocked_queue, lu_task); + if (r_ptr == NULL) { + if (need_signal) + pthread_cond_signal(&spec->cmd_queue_cond); + need_signal = 0; + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("queue_enqueue() failed\n"); + goto error_return; + } + } + if (need_signal) + pthread_cond_signal(&spec->maint_cmd_queue_cond); + MTX_UNLOCK(&spec->complete_queue_mutex); + + /* check wait task */ + MTX_LOCK(&spec->wait_lu_task_mutex); + for(k = 0; k < ISTGT_MAX_NUM_LUWORKERS; k++) { + lu_task = spec->wait_lu_task[k]; + if (lu_task != NULL) { + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + /* conn had gone? */ + MTX_LOCK(&lu_task->trans_mutex); + { + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu aborted\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + /* force error */ + lu_task->error = 1; + lu_task->abort = 1; + lu_task->lu_cmd.aborted = 1; + cleared++; + rc = pthread_cond_signal(&lu_task->trans_cond); + if (rc != 0) { + /* ignore error */ + rc = 0; + } + } + MTX_UNLOCK(&lu_task->trans_mutex); + } + } + } + MTX_UNLOCK(&spec->wait_lu_task_mutex); + + + for (i=0; iluworkers+1; i++) { + MTX_LOCK(&spec->luworker_mutex[i]); + if (spec->inflight_io[i] != NULL) { + lu_task = spec->inflight_io[i]; + lu_cmd = &(lu_task->lu_cmd); + ln = 0; + if(rem > 30) + ln = snprintf(bp, rem, "%dC0x%x CS%d TA%d.%d TS%d 0x%x(lba:%lx+%x)%lu.%lu[%c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld %c:%ld.%9.9ld] ", i, + lu_task->lu_cmd.CmdSN, lu_task->lu_cmd.status, lu_task->execute, lu_task->use_cond, spec->luworker_waiting[i], + lu_task->lu_cmd.cdb[0], lu_task->lu_cmd.lba, + lu_task->lu_cmd.lblen, + (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec), + (now.tv_nsec - lu_task->lu_cmd.create_time.tv_nsec), + lu_cmd->caller[1] ? lu_cmd->caller[1] : '9', lu_cmd->tdiff[1].tv_sec, lu_cmd->tdiff[1].tv_nsec, + lu_cmd->caller[2] ? lu_cmd->caller[2] : '9', lu_cmd->tdiff[2].tv_sec, lu_cmd->tdiff[2].tv_nsec, + lu_cmd->caller[3] ? lu_cmd->caller[3] : '9', lu_cmd->tdiff[3].tv_sec, lu_cmd->tdiff[3].tv_nsec, + lu_cmd->caller[4] ? lu_cmd->caller[4] : '9', lu_cmd->tdiff[4].tv_sec, lu_cmd->tdiff[4].tv_nsec, + lu_cmd->caller[5] ? lu_cmd->caller[5] : '9', lu_cmd->tdiff[5].tv_sec, lu_cmd->tdiff[5].tv_nsec, + lu_cmd->caller[6] ? lu_cmd->caller[6] : '9', lu_cmd->tdiff[6].tv_sec, lu_cmd->tdiff[6].tv_nsec, + lu_cmd->caller[7] ? lu_cmd->caller[7] : '9', lu_cmd->tdiff[7].tv_sec, lu_cmd->tdiff[7].tv_nsec, + lu_cmd->caller[8] ? lu_cmd->caller[8] : '9', lu_cmd->tdiff[8].tv_sec, lu_cmd->tdiff[8].tv_nsec + ); + if(ln <0) + ln = 0; + else if(ln > rem) + ln = rem; + rem -= ln; + bp += ln; + *bp = '\0'; + if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN)) + && (lu_task->in_plen == ilen && (strcasecmp(lu_task->in_port, initiator_port) == 0))) { + ISTGT_ERRLOG("cmd 0x%x to abort matches with inflight %d abort:%d:%d\n", lu_task->lu_cmd.CmdSN, i, lu_task->abort, lu_cmd->aborted); + + if(lu_cmd->aborted == 1) + goto avoidif; + + if(wait_inflights == 1) { + MTX_UNLOCK(&spec->luworker_mutex[i]); + MTX_LOCK(&spec->lu_tmf_mutex[i]); + spec->lu_tmf_wait[i] = 1; + now_wait = time(NULL); + abstime.tv_sec = now_wait + TMF_TIMEOUT; + abstime.tv_nsec = 0; + if(already_waited == 0){ + rc = pthread_cond_timedwait(&spec->lu_tmf_cond[i],&spec->lu_tmf_mutex[i], &abstime); + if(rc == ETIMEDOUT) { + ISTGT_LOG("TMF_WAIT ETIMEDOUT: Aborting cmd 0x%x\n", CmdSN); + already_waited = 1; + } else { + ISTGT_LOG("Not Aborting cmd 0x%x, Successfully came out of inflight\n", CmdSN); + } + } + if(spec->lu_tmf_wait[i] == 1 || already_waited == 1) { + if((abort_release == 1) && ((lu_cmd->cdb[0] == SPC2_RELEASE_6) || (lu_cmd->cdb[0] == SPC2_RELEASE_10))) { + lu_cmd->release_aborted = 1; + ISTGT_LOG("CmdSN(0x%x), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu Release cleared from blockedq\n", + lu_cmd->CmdSN, + lu_cmd->cdb[0], + lu_cmd->lba, lu_cmd->lblen, + (now.tv_sec - lu_cmd->create_time.tv_sec)); + } else { + lu_cmd->aborted = 1; + } + if(lu_task->abort != 1) + cleared++; + } + MTX_UNLOCK(&spec->lu_tmf_mutex[i]); + continue; + } + else + { + lu_cmd->aborted = 1; + if(lu_task->abort != 1) + cleared++; + } +avoidif: + ; + } + } + else if(spec->inflight_io[i] == NULL) + { + ln = 0; + if(rem > 30) + ln = snprintf(bp, rem, "%dTS%d ", i, spec->luworker_waiting[i]); + if(ln < 0) + ln = 0; + else if(ln > rem) + ln = rem; + rem -= ln; + bp += ln; + *bp = '\0'; + } + MTX_UNLOCK(&spec->luworker_mutex[i]); + } + if(conn!=NULL && conn->state != CONN_STATE_EXITING && abort_result_queue == 1) { + MTX_LOCK(&conn->result_queue_mutex); + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&conn->result_queue, &cookie)) != NULL) { + if(tptr->lu_cmd.CmdSN == CmdSN){ + tptr->lu_cmd.aborted = 1; + cleared++; + break; + } + } + MTX_UNLOCK(&conn->result_queue_mutex); + } + + if (rem != 2040) { + used = (bp - buf) + 2; + if(used > 900) + { + c = buf[900]; + buf[900] = '\0'; + } + ISTGT_ERRLOG("inflight-aborted dskRef:%d inflight:%d errCnt: %d freeMatrix0: %d freeMatrix1: %d schdlrWaiting: %d schdlrCmdWaiting: %d %s\n", + spec->ludsk_ref, spec->inflight, spec->error_count, + spec->lu_free_matrix[0], spec->lu_free_matrix[1], spec->schdler_waiting, spec->schdler_cmd_waiting, buf); + if(used > 900) + { + buf[900] = c; + ISTGT_ERRLOG("%s\n", buf+900); + } + } + +error_return: + if (istgt_queue_count(&saved_queue) == 0 ) { + + istgt_queue_destroy(&saved_queue); + } + else { + ISTGT_ERRLOG("temporary queue is not empty\n"); + rc = -1; + } + + if (istgt_queue_count(&saved_bqueue) == 0) { + istgt_queue_destroy(&saved_bqueue); + } + else { + ISTGT_ERRLOG("temporary bqueue is not empty\n"); + rc = -1; + } + if (istgt_queue_count(&saved_queue1) == 0 ) { + + istgt_queue_destroy(&saved_queue1); + } + else { + ISTGT_ERRLOG("temporary queue is not empty\n"); + rc = -1; + } + + if (istgt_queue_count(&saved_bqueue1) == 0) { + istgt_queue_destroy(&saved_bqueue1); + } + else { + ISTGT_ERRLOG("temporary bqueue is not empty\n"); + rc = -1; + } + return cleared; +} + +static int +istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port) +{ + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue abort by port=%s\n", + initiator_port); + + rc = istgt_lu_disk_queue_clear_internal(NULL, spec, initiator_port, + 1, 0U); /* ALL, CmdSN=0 */ + return rc; +} + +int +istgt_lu_disk_queue_clear_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu) +{ + ISTGT_LU_DISK *spec; + int cleared = 0; + int i; + + if (lu == NULL) + return -1; + + for (i = 0; i < lu->maxlun; i++) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n", + lu->num, i); +#endif + continue; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[i].spec; + if (spec == NULL) { + continue; + } + + cleared = istgt_lu_disk_queue_clear_ITL(conn, lu, i); + if (cleared < 0) { + return -1; + } + } + + return cleared; +} + +int +istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_DISK *spec; + int cleared = 0; + + if (lu == NULL) + return -1; + if (lun >= lu->maxlun) + return -1; + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n", + conn->initiator_name, conn->initiator_port); + + cleared = istgt_lu_disk_queue_clear_internal(conn, spec, conn->initiator_port, + 1, 0U); /* ALL, CmdSN=0 */ + return cleared; +} + +int +istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun, uint32_t CmdSN) +{ + ISTGT_LU_DISK *spec; + int cleared = 0; + + if (lu == NULL) + return -1; + if (lun >= lu->maxlun) + return -1; + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n", + conn->initiator_name, conn->initiator_port); + + cleared = istgt_lu_disk_queue_clear_internal(conn, spec, conn->initiator_port, + 0, CmdSN); + return cleared; +} + +int +istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu, int lun) +{ + ISTGT_LU_TASK_Ptr lu_task; + ISTGT_LU_DISK *spec; + struct timespec now; + int rc = 0, cleared = 0; + int k; + + if (lu == NULL) + return -1; + if (lun >= lu->maxlun) + return -1; + + if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) { + return -1; + } + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + + clock_gettime(clockid, &now); + MTX_LOCK(&spec->complete_queue_mutex); + while (1) { + lu_task = istgt_queue_dequeue(&spec->cmd_queue); + if (lu_task == NULL) + break; + ISTGT_LOG("CmdSN(%u), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + return -1; + } + cleared++; + } + /* Clear all the commads that are blocked */ + while(1) { + lu_task = istgt_queue_dequeue(&spec->blocked_queue); + if (lu_task == NULL) + break; + ISTGT_LOG("CmdSN(%u), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + return -1; + } + cleared++; + } + + while (1) { + lu_task = istgt_queue_dequeue(&spec->maint_cmd_queue); + if (lu_task == NULL) + break; + ISTGT_LOG("CmdSN(%u), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + return -1; + } + cleared++; + } + /* Clear all the commads that are blocked */ + while(1) { + lu_task = istgt_queue_dequeue(&spec->maint_blocked_queue); + if (lu_task == NULL) + break; + ISTGT_LOG("CmdSN(%u), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu cleared\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + MTX_UNLOCK(&spec->complete_queue_mutex); + ISTGT_ERRLOG("lu_destory_task() failed\n"); + return -1; + } + cleared++; + } + MTX_UNLOCK(&spec->complete_queue_mutex); + + /* check wait task */ + MTX_LOCK(&spec->wait_lu_task_mutex); + for(k = 0; k < ISTGT_MAX_NUM_LUWORKERS; k++) { + lu_task = spec->wait_lu_task[k]; + if (lu_task != NULL) { + /* conn had gone? */ + rc = pthread_mutex_trylock(&lu_task->trans_mutex); + if (rc == 0) { + ISTGT_LOG("CmdSN(%u), OP=0x%x (lba %"PRIu64", %u blocks), ElapsedTime=%lu aborted\n", + lu_task->lu_cmd.CmdSN, + lu_task->lu_cmd.cdb[0], + lu_task->lu_cmd.lba, lu_task->lu_cmd.lblen, + (unsigned long) (now.tv_sec - lu_task->lu_cmd.create_time.tv_sec)); + /* force error */ + lu_task->error = 1; + lu_task->abort = 1; + cleared++; + rc = pthread_cond_signal(&lu_task->trans_cond); + if (rc != 0) { + /* ignore error */ + } + MTX_UNLOCK(&lu_task->trans_mutex); + } + } + } + MTX_UNLOCK(&spec->wait_lu_task_mutex); + + return rc == 0 ? cleared : rc; +} + +/* + * Incoming request encounter a conflict if there are already blocked entries + * or if the currently executed items conflict with the incoming items + * Note that we do this to avoid severe pipeline hazards in the order of execution. + */ + +char qact[8][20] = { + "BLOCK", + "BLOCK_OVERLAP", + "BLOCK_OVERLAP_TAG", + "BLOCK_SUSPECT", + "PASS", + "SKIP", + "ERROR", + "UNK" +}; + +int +istgt_lu_print_q(ISTGT_LU_Ptr lu, int lun) +{ +#define adjbuf() { \ + if (wn < 0) \ + wn = 0; \ + else if (wn > brem) \ + wn = brem; \ + bptr += wn; \ + brem -= wn; \ +} +#define tdiff(_s, _n, _r) { \ + if ((_n.tv_nsec - _s.tv_nsec) < 0) { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec-1; \ + _r.tv_nsec = 1000000000 + _n.tv_nsec - _s.tv_nsec; \ + } else { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec; \ + _r.tv_nsec = _n.tv_nsec - _s.tv_nsec; \ + } \ +} +#define _BSZ_ 4086 + char buf[_BSZ_+10]; + int brem = _BSZ_, wn = 0; + int toprint, chunk; + char *bptr = buf; + int i = 0; + + ISTGT_LU_DISK *spec; + ISTGT_LU_TASK_Ptr tptr; + void *cookie=NULL; + struct timespec now; + struct timespec r; + + if (lu == NULL) + return -1; + if (lun >= lu->maxlun) + return -1; + if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) { + return -1; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + return -1; + + uint64_t gb_size = spec->size / ISTGT_LU_1GB; + uint64_t mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB; + + MTX_LOCK(&spec->complete_queue_mutex); + int rpm = lu->lun[lun].rotationrate; + int cq = istgt_queue_count(&spec->cmd_queue); + int bq = istgt_queue_count(&spec->blocked_queue); + int cq1 = istgt_queue_count(&spec->maint_cmd_queue); + int bq1 = istgt_queue_count(&spec->maint_blocked_queue); + int inf = spec->ludsk_ref; + + clock_gettime(clockid, &now); + wn = snprintf(bptr, brem, " cmdQ:%d:%d blked:%d:%d inf:%d", cq, cq1, bq, bq1, inf); + adjbuf() + + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->cmd_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + cookie = NULL; + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->blocked_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + + cookie = NULL; + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->maint_cmd_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + cookie = NULL; + while ((tptr= (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->maint_blocked_queue, &cookie)) != NULL) { + tdiff(tptr->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i++, tptr->lu_cmd.CmdSN, tptr->lu_cmd.cdb0, + tptr->lu_cmd.lba, tptr->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + MTX_UNLOCK(&spec->complete_queue_mutex); + + + /* luworker waiting data from zvol */ + for (i=0; i < spec->luworkers+1; i++ ) { + MTX_LOCK(&spec->luworker_mutex[i]); + if(spec->inflight_io[i] != NULL) { + tdiff(spec->inflight_io[i]->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i, spec->inflight_io[i]->lu_cmd.CmdSN, + spec->inflight_io[i]->lu_cmd.cdb0, + spec->inflight_io[i]->lu_cmd.lba, + spec->inflight_io[i]->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + MTX_UNLOCK(&spec->luworker_mutex[i]); + } + *bptr++ = ' '; *bptr++ = '-'; *bptr++ = ' '; brem-=3; + /* luworker waiting data from network */ + MTX_LOCK(&spec->wait_lu_task_mutex); + for (i=0; i < ISTGT_MAX_NUM_LUWORKERS; i++ ) { + if (spec->wait_lu_task[i] != NULL) { + tdiff(spec->wait_lu_task[i]->lu_cmd.times[0], now, r) + wn = snprintf(bptr, brem, " %d:%x 0x%x.%lu+%uT%ld.%9.9ld", + i, spec->wait_lu_task[i]->lu_cmd.CmdSN, + spec->wait_lu_task[i]->lu_cmd.cdb0, + spec->wait_lu_task[i]->lu_cmd.lba, + spec->wait_lu_task[i]->lu_cmd.lblen, + r.tv_sec, r.tv_nsec); + adjbuf() + } + } + MTX_UNLOCK(&spec->wait_lu_task_mutex); + + ISTGT_NOTICELOG("LU%d:QUE %s %s [%s, %luGB.%luMB, %lu blks of %lu bytes, phy:%u %s%s%s%s%s%s%s rpm:%d] q:%d thr:%d/%d inflight:%d %d/%d\n", + lu->num, lu->name ? lu->name : "-", lu->readonly ? "readonly " : "", + spec->file, gb_size, mb_size, spec->blockcnt, spec->blocklen, spec->rshift, + spec->readcache ? "" : "RCD", spec->writecache ? " WCE" : "", + spec->ats ? " ATS" : "",spec->xcopy ? " XCOPY" : "", spec->unmap ? " UNMAP" : "", + spec->wsame ? " WSAME" : "", spec->dpofua ? " DPOFUA" : "", + rpm, spec->queue_depth, spec->luworkers, spec->luworkersActive, spec->ludsk_ref, + brem, _BSZ_ - brem); + + + toprint = _BSZ_ - brem; + bptr = buf; + i = 0; + while(toprint > 0) + { + if (toprint > 1023) + chunk = 1024; + else + chunk = toprint; + ISTGT_NOTICELOG("LU%d:QUE%d %.*s", lu->num, i, chunk, bptr); + toprint -= chunk; + bptr += chunk; + ++i; + } + return 0; +} + +static inline istgt_task_action +istgt_check_for_blockage(ISTGT_LU_TASK_Ptr pending_task, ISTGT_LU_TASK_Ptr ooa_task) +{ + struct istgt_cmd_entry *pending_entry, *ooa_entry; + istgt_serialize_action *serialize_row; + istgt_tag_type const ptype = pending_task->lu_cmd.Attr_bit; + istgt_tag_type const otype = ooa_task->lu_cmd.Attr_bit; + /* + * The initiator attempted multiple untagged commands at the same + * time. Can't do that. + */ + if ((ptype == ISTGT_TAG_UNTAGGED) + && (otype == ISTGT_TAG_UNTAGGED) + && ((pending_task->in_plen == ooa_task->in_plen) && + (strcmp(pending_task->in_port, ooa_task->in_port) == 0)) + && ((ooa_task->flags & ISTGT_FLAG_ABORT) == 0)) + return (ISTGT_TASK_OVERLAP); + + /* + * The initiator attempted to send multiple tagged commands with + * the same ID. (It's fine if different initiators have the same + * tag ID.) + * + * Even if all of those conditions are true, we don't kill the I/O + * if the command ahead of us has been aborted. We won't end up + * sending it to the FETD, and it's perfectly legal to resend a + * command with the same tag number as long as the previous + * instance of this tag number has been aborted somehow. + */ + if ((ptype!= ISTGT_TAG_UNTAGGED) + && (otype != ISTGT_TAG_UNTAGGED) + && (ptype == otype) + && (pending_task->lu_cmd.task_tag == ooa_task->lu_cmd.task_tag) + && ((pending_task->in_plen == ooa_task->in_plen) && + (strcmp(pending_task->in_port, ooa_task->in_port) == 0)) + && ((ooa_task->flags & ISTGT_FLAG_ABORT) == 0)) + return (ISTGT_TASK_OVERLAP_TAG); + + /* + * If we get a head of queue tag, SAM-3 says that we should + * immediately execute it. + * + * What happens if this command would normally block for some other + * reason? e.g. a request sense with a head of queue tag + * immediately after a write. Normally that would block, but this + * will result in its getting executed immediately... + * + * We currently return "pass" instead of "skip", so we'll end up + * going through the rest of the queue to check for overlapped tags. + * + * XXX KDM check for other types of blockage first?? + */ + if (ptype == ISTGT_TAG_HEAD_OF_QUEUE) + return (ISTGT_TASK_PASS); + + /* + * Ordered tags have to block until all items ahead of them + * have completed. If we get called with an ordered tag, we always + * block, if something else is ahead of us in the queue. + */ + if (ptype == ISTGT_TAG_ORDERED) + return (ISTGT_TASK_BLOCK); + + /* + * Simple tags get blocked until all head of queue and ordered tags + * ahead of them have completed. I'm lumping untagged commands in + * with simple tags here. XXX KDM is that the right thing to do? + */ + if (((ptype == ISTGT_TAG_UNTAGGED) + || (ptype== ISTGT_TAG_SIMPLE)) + && ((otype == ISTGT_TAG_HEAD_OF_QUEUE) + || (otype == ISTGT_TAG_ORDERED))) + return (ISTGT_TASK_BLOCK); + + pending_entry = &istgt_cmd_table[pending_task->lu_cmd.cdb[0]]; + ooa_entry = &istgt_cmd_table[ooa_task->lu_cmd.cdb[0]]; + + serialize_row = istgt_serialize_table[ooa_entry->seridx]; + + switch (serialize_row[pending_entry->seridx]) { + case ISTGT_SER_BLOCK: + return (ISTGT_TASK_BLOCK); + break; /* NOTREACHED */ + case ISTGT_SER_EXTENT: + if (pending_task->cdb0 == 0xFF || ooa_task->cdb0 == 0xFF) + return (ISTGT_TASK_BLOCK_SUSPECT); //this is a suspect case + else if ( (pending_task->lbE < ooa_task->lba) || + (ooa_task->lbE < pending_task->lba) ) + return (ISTGT_TASK_PASS); + else + return (ISTGT_TASK_BLOCK); + break; /* NOTREACHED */ + case ISTGT_SER_PASS: + return (ISTGT_TASK_PASS); + break; /* NOTREACHED */ + case ISTGT_SER_SKIP: + return (ISTGT_TASK_SKIP); + break; + default: + ISTGT_ERRLOG("invalid serialization value %d", + serialize_row[pending_entry->seridx]); + break; + } + ISTGT_ERRLOG("Could not find the serialization value %d", + serialize_row[pending_entry->seridx]); + return (ISTGT_TASK_ERROR); +} + +/* cmd_queue_mutex is required */ +istgt_task_action istgt_check_for_istgt_queue(ISTGT_QUEUE_Ptr queue, ISTGT_LU_TASK_Ptr unblocked_lu_task) +{ + ISTGT_LU_TASK_Ptr cmd_lu_task; + void *cookie; + istgt_task_action action; + action = ISTGT_TASK_PASS; + cookie = NULL; + while ((cmd_lu_task = (ISTGT_LU_TASK_Ptr)istgt_queue_walk(queue, &cookie))) { + action = istgt_check_for_blockage(unblocked_lu_task,cmd_lu_task); + if (action != ISTGT_TASK_SKIP && action != ISTGT_TASK_PASS) { + return action; + } + } + return action; +} + +istgt_task_action istgt_check_for_all_luworkers(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task) +{ + int i; + istgt_task_action action = ISTGT_TASK_PASS; + ISTGT_LU_TASK_Ptr inflight_task; + for (i=0; i < spec->luworkers; i++ ) { + MTX_LOCK(&spec->luworker_mutex[i]); + if(spec->inflight_io[i] == NULL){ + MTX_UNLOCK(&spec->luworker_mutex[i]); + continue; + } + inflight_task = spec->inflight_io[i]; + action = istgt_check_for_blockage(unblocked_lu_task, inflight_task); + MTX_UNLOCK(&spec->luworker_mutex[i]); + if (action != ISTGT_TASK_SKIP && action != ISTGT_TASK_PASS) { + return action; + } + } + return action; +} + +istgt_task_action istgt_check_for_all_maint_luworkers(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task) +{ + int i; + istgt_task_action action = ISTGT_TASK_PASS; + ISTGT_LU_TASK_Ptr inflight_task; + for (i=spec->luworkers; i < (spec->luworkers + 1); i++ ) { + MTX_LOCK(&spec->luworker_mutex[i]); + if(spec->inflight_io[i] == NULL){ + MTX_UNLOCK(&spec->luworker_mutex[i]); + continue; + } + inflight_task = spec->inflight_io[i]; + action = istgt_check_for_blockage(unblocked_lu_task, inflight_task); + MTX_UNLOCK(&spec->luworker_mutex[i]); + if (action != ISTGT_TASK_SKIP && action != ISTGT_TASK_PASS) { + return action; + } + } + return action; +} +/*Check if the IO is blocked by any IO which came before it +Reverse walk beacuse we want to put the maintenance IOs just after the last IO which is blocking it +cookie = NULL;//When the IO has just arrived +cookie = istgt_get_prev_qptr(unblocked_lu_task->complete_queue_ptr);//While Scheduling blocked IOs +*/ +istgt_task_action istgt_check_for_parallel_ios(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task) +{ + ISTGT_LU_TASK_Ptr lu_task; + ISTGT_QUEUE_Ptr queue = &spec->complete_queue; + void *cookie; + istgt_task_action action; + action = ISTGT_TASK_PASS; + if(unblocked_lu_task->lu_cmd.flags == 0) + cookie = NULL; + else + cookie = istgt_get_prev_qptr(unblocked_lu_task->complete_queue_ptr); + while ((lu_task = (ISTGT_LU_TASK_Ptr)istgt_queue_reverse_walk(queue, &cookie))) { + action = istgt_check_for_blockage(unblocked_lu_task,lu_task); + if (action != ISTGT_TASK_SKIP && action != ISTGT_TASK_PASS) { + unblocked_lu_task->blocked_by = istgt_get_next_qptr(cookie); + return action; + } + } + unblocked_lu_task->blocked_by = NULL; + return action; +} + +int is_maintenance_io(ISTGT_LU_TASK_Ptr task) +{ + switch(task->lu_cmd.cdb[0]) + { + case 0x00: /* 00 TEST UNIT READY */ + case 0x12: /* 12 INQUIRY */ + case 0xA0: /* A0 REPORT LUNS */ + case 0x03: /* 03 REQUEST SENSE */ + case 0x4D: /* 4D LOG SENSE */ + case 0x15: /* 15 MODE SELECT 6 */ + case 0x55: /* 55 MODE SELECT 10 */ + case 0x1a: /* 1a MODE SENSE 6 */ + case 0x5a: /* 5a MODE SENSE 10 */ + case 0xa3: /* a3 MAINTENANCE IN */ + return 1; + default: + return 0; + } + return 0; +} +/*If it is a maintenance IO and is blocked we will enqueue it just after the IO +which is blocking it in complete queue, else normal enqueue at the end +*/ +static istgt_task_action +istgt_is_exec_pipeline_conflict(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr pending_task) +{ + ISTGT_QUEUE_Ptr r_ptr; + istgt_task_action action; + + if(!is_maintenance_io(pending_task)) + { + if((istgt_queue_count(&spec->blocked_queue) != 0) || + (istgt_queue_count(&spec->maint_blocked_queue) != 0)){ + if(spec->do_avg == 1) + { + spec->avgs[18].count++; + } + r_ptr = istgt_queue_enqueue(&spec->complete_queue, pending_task); + pending_task->complete_queue_ptr = r_ptr; + return ISTGT_TASK_BLOCK; + } + } + action = istgt_check_for_parallel_ios(spec, pending_task); + switch (action) { + case ISTGT_TASK_BLOCK: + case ISTGT_TASK_OVERLAP: + case ISTGT_TASK_OVERLAP_TAG: + case ISTGT_TASK_ERROR: + case ISTGT_TASK_BLOCK_SUSPECT: + if(is_maintenance_io(pending_task)) { + r_ptr = istgt_queue_enqueue_after(&spec->complete_queue, pending_task->blocked_by, pending_task); + pending_task->blocked_by = NULL; + pending_task->complete_queue_ptr = r_ptr; + } else { + r_ptr = istgt_queue_enqueue(&spec->complete_queue, pending_task); + pending_task->complete_queue_ptr = r_ptr; + } + if(spec->do_avg == 1) + { + spec->avgs[18].tot_sec++; + } + return (action); + case ISTGT_TASK_SKIP: + case ISTGT_TASK_PASS: + r_ptr = istgt_queue_enqueue(&spec->complete_queue, pending_task); + pending_task->complete_queue_ptr = r_ptr; + break; + default: + ISTGT_ERRLOG("Invalid action in exec_pipeline for cmdsn:%x\n", pending_task->lu_cmd.CmdSN); + break; + } + return (ISTGT_TASK_PASS); +} +/*Scheduling maintenance commands--If the first cmd in the complete queue is maint, +we will find that command in the maint_blocked_queue and move it to maint_cmd_queue. + +Scheduling normal commands --We examine utmost 2 blocked entries so as not to have a n*2 unblocking. Eventually +every 1 request ejected out of the cmd queue would inturn schedule 2 requests and +hence we have a exponential reschedules for blocked items. This will drain the blocked +queue in reasonable time +*/ + +void +istgt_schedule_blocked_requests(ISTGT_LU_DISK *spec, ISTGT_QUEUE_Ptr cmd_queue, ISTGT_QUEUE_Ptr blocked_queue, int maint) +{ + ISTGT_LU_TASK_Ptr unblocked_lu_task, lu_task; + void *cookie1 = NULL; + void *cookie2 = NULL; + istgt_task_action action; + int todo_count=3; + int unblocked = 0; + + if(spec == NULL || cmd_queue == NULL || blocked_queue == NULL) + return; + /*Since we have only one maintenance thread*/ + if( maint == 1) { + if((lu_task = (ISTGT_LU_TASK_Ptr)istgt_queue_walk(&spec->complete_queue, &cookie1))) { + if(is_maintenance_io(lu_task)) { + while ((unblocked_lu_task = (ISTGT_LU_TASK_Ptr)istgt_queue_walk(blocked_queue, &cookie2))) { + if(unblocked_lu_task == lu_task ) { + istgt_queue_dequeue_middle(blocked_queue, istgt_get_prev_qptr(cookie2)); + ++unblocked; + unblocked_lu_task->lu_cmd.flags |= ISTGT_UNBLOCKED; + timediffw(&unblocked_lu_task->lu_cmd, 'U'); + istgt_queue_enqueue(cmd_queue, unblocked_lu_task); //dequeue from maint blocked queue + break; + } + } + if(unblocked == 0) + ISTGT_ERRLOG("task not found in blocked_q\n"); + } + } + }else { + if (istgt_queue_count(blocked_queue)!=0) { + while (todo_count--) { + unblocked_lu_task = istgt_queue_dequeue(blocked_queue); + if(unblocked_lu_task == NULL) + break; + + action = istgt_check_for_parallel_ios(spec, unblocked_lu_task); + if(action != ISTGT_TASK_SKIP && action != ISTGT_TASK_PASS) + { + istgt_queue_enqueue_first(blocked_queue,unblocked_lu_task); + goto unlock_return; + } + /*All inflight request to disk should be checked for conflict */ + ++unblocked; + unblocked_lu_task->lu_cmd.flags |= ISTGT_UNBLOCKED; + timediffw(&unblocked_lu_task->lu_cmd, 'U'); + istgt_queue_enqueue(cmd_queue, unblocked_lu_task); + } + } + } +unlock_return: + return; +} + +int +istgt_lu_disk_signal_worker(ISTGT_LU_Ptr lu) +{ + int rc = 0; + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Signal the LU%d worker", lu->num); + MTX_LOCK(&lu->queue_mutex); + lu->queue_check = 1; + rc = pthread_cond_signal(&lu->queue_cond); + MTX_UNLOCK(&lu->queue_mutex); + if (rc != 0) { + ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num); + return -1; + } + return 0; +} + +int +istgt_lu_disk_queue(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_QUEUE_Ptr r_ptr; + ISTGT_LU_TASK_Ptr lu_task; + ISTGT_LU_Ptr lu; + ISTGT_LU_DISK *spec; + uint8_t *data = NULL; + uint8_t *cdb; + uint32_t allocation_len; + int data_len; + int data_alloc_len = 1024 * 1024 * 1; + int lun_i; + int maxq; + int qcnt, ccnt, bcnt, icnt; + int rc; + const char *msg = ""; + istgt_task_action action; + int sindx = 7; + ISTGT_QUEUE_Ptr q; + struct timespec sch1, sch2, r; + int id; + unsigned long secs, nsecs; +#define ttdiff(_s, _n, _r) { \ + if(unlikely(spec->do_avg == 1)) \ + { \ + if ((_n.tv_nsec - _s.tv_nsec) < 0) { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec-1; \ + _r.tv_nsec = 1000000000 + _n.tv_nsec - _s.tv_nsec; \ + } else { \ + _r.tv_sec = _n.tv_sec - _s.tv_sec; \ + _r.tv_nsec = _n.tv_nsec - _s.tv_nsec; \ + } \ + spec->avgs[id].count++; \ + spec->avgs[id].tot_sec += _r.tv_sec; \ + spec->avgs[id].tot_nsec += _r.tv_nsec; \ + secs = spec->avgs[id].tot_nsec/1000000000; \ + nsecs = spec->avgs[id].tot_nsec%1000000000; \ + spec->avgs[id].tot_sec += secs; \ + spec->avgs[id].tot_nsec = nsecs; \ + } \ +} + + if (lu_cmd == NULL) + return -1; + lu = lu_cmd->lu; + if (lu == NULL) { + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + spec = NULL; + cdb = lu_cmd->cdb; + //data = lu_cmd->data; + //data_alloc_len = lu_cmd->alloc_len; + + lun_i = istgt_lu_islun2lun(lu_cmd->lun); + if (lun_i >= lu->maxlun) { +/* + ISTGT_ERRLOG("LU%d: LUN%4.4d invalid\n", lu->num, lun_i); +*/ + if (cdb[0] == SPC_INQUIRY) { + allocation_len = DGET16(&cdb[3]); + if (allocation_len > (size_t) data_alloc_len) { + ISTGT_ERRLOG("alloc_len %d too big\n", allocation_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data_len = 96; + data = lu_cmd->data = xmalloc(data_len + 200); + memset(data, 0, data_len+200); + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], 0x03, 7, 3); + BDADD8W(&data[0], 0x1f, 4, 5); + memset(&data[1], 0, data_len - 1); + /* ADDITIONAL LENGTH */ + data[4] = data_len - 5; + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + return ISTGT_LU_TASK_RESULT_IMMEDIATE; + } else { + /* LOGICAL UNIT NOT SUPPORTED */ + ISTGT_ERRLOG("istgt_lu_disk_queue: Illegal_Request, lun_i %d maxlun %d \n", lun_i , lu->maxlun); + BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return ISTGT_LU_TASK_RESULT_IMMEDIATE; + } + } + spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec; + if (spec == NULL) { + /* LOGICAL UNIT NOT SUPPORTED */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return ISTGT_LU_TASK_RESULT_IMMEDIATE; + } + /* ready to enqueue, spec is valid for LUN access */ + + /* allocate task and copy LU_CMD(PDU) */ + lu_task = istgt_lu_create_task(conn, lu_cmd, lun_i, spec); + if (lu_task == NULL) { + ISTGT_ERRLOG("lu_create_task() failed\n"); + return -1; + } + + /* enqueue SCSI command */ + timediff(&lu_task->lu_cmd, 'e', __LINE__); + MTX_LOCK(&spec->complete_queue_mutex); + ccnt = istgt_queue_count(&spec->cmd_queue); + bcnt = istgt_queue_count(&spec->blocked_queue); + ccnt += istgt_queue_count(&spec->maint_cmd_queue); + bcnt += istgt_queue_count(&spec->maint_blocked_queue); + qcnt = ccnt + bcnt; + icnt = spec->ludsk_ref; + maxq = spec->queue_depth * lu->istgt->MaxSessions; + if (qcnt > maxq) { + MTX_UNLOCK(&spec->complete_queue_mutex); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_TASK_SET_FULL; + ISTGT_ERRLOG("ISTGT_LU_TASK_RESULT_QUEUE_FULL: cq#%d bq#%d max#%d\n", + ccnt, bcnt, maxq); + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + return -1; + } + if(spec->schdler_cmd_waiting) { + rc = pthread_cond_signal(&spec->cmd_queue_cond); + } + if (rc < 0) { + ISTGT_ERRLOG("LU%d:Failed to signal worker\n", lu->num); + } + return ISTGT_LU_TASK_RESULT_QUEUE_FULL; + } + lu_task->lu_cmd.flags = 0; + action = istgt_is_exec_pipeline_conflict(spec, lu_task); + sindx = action; + if(is_maintenance_io(lu_task)) + q = &spec->maint_cmd_queue; + else + q = &spec->cmd_queue; + switch( action ){ + case ISTGT_TASK_PASS: + case ISTGT_TASK_SKIP: + if(is_maintenance_io(lu_task)) + lu_task->lu_cmd.flags |= ISTGT_ADD_TO_MAINT; + else + lu_task->lu_cmd.flags |= ISTGT_ADD_TO_CMD; + break; + case ISTGT_TASK_BLOCK_SUSPECT: + case ISTGT_TASK_BLOCK: + case ISTGT_TASK_OVERLAP: + /* BUILD SENSE illegal_request asc = 0x4E, ascq = 0x00 */ + case ISTGT_TASK_OVERLAP_TAG: + /* BUILD SENSE illegal_request asc = 0x4D, ascq = task_tag */ + lu_task->flags |= ISTGT_FLAG_BLOCKED; + if(is_maintenance_io(lu_task)) + { + lu_task->lu_cmd.flags |= (ISTGT_ADD_TO_BLOCKED_MAINT); + q = &spec->maint_blocked_queue; + } + else + { + lu_task->lu_cmd.flags |= (ISTGT_ADD_TO_BLOCKED_CMD); + q = &spec->blocked_queue; + } + if(spec->do_avg == 1) + spec->avgs[10].count++; + break; + case ISTGT_TASK_ERROR: + /* Internal Failure */ + default: + //assert(!"Internal failure"); + BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ISTGT_ERRLOG("LU%d: Queue%s: Task_error (q:%d/%d %d), CmdSN=%u, OP=0x%x (lba %"PRIu64", blks:%u), LUN=0x%16.16"PRIx64"\n", + lu->num, qact[sindx < 0 || sindx > 6 ? 7 : sindx], ccnt, bcnt, icnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lba, lu_cmd->lblen, lu_cmd->lun); + if(action == ISTGT_TASK_ERROR) + goto error_return; + else + goto error_return_no_dequeue; + } + + /* enqueue task to LUN */ + switch (lu_cmd->Attr_bit) { + case 0x03: /* Head of Queue */ + msg = "HeadofQueue"; + if(is_maintenance_io(lu_task)) + r_ptr = istgt_queue_enqueue_first(&spec->maint_cmd_queue, lu_task); + else + r_ptr = istgt_queue_enqueue_first(&spec->cmd_queue, lu_task); + break; + case 0x00: /* Untagged */ + msg = "Untagged"; + r_ptr = istgt_queue_enqueue(q, lu_task); + break; + case 0x01: /* Simple */ + msg = "Simple"; + r_ptr = istgt_queue_enqueue(q, lu_task); + break; + case 0x02: /* Ordered */ + msg = "Ordered"; + r_ptr = istgt_queue_enqueue(q, lu_task); + break; + case 0x04: /* ACA */ + msg = "ACA"; + r_ptr = istgt_queue_enqueue(q, lu_task); + break; + default: /* Reserved */ + msg = "Reserved"; + r_ptr = istgt_queue_enqueue(q, lu_task); + break; + } + if (r_ptr == NULL) { + ISTGT_ERRLOG("LU%d: Queue%s enqerror(%s)(q:%d/%d %d) CmdSN=%u,0x%x.%lu+%u\n", + lu->num, qact[sindx < 0 || sindx > 6 ? 7 : sindx], msg, ccnt, bcnt, icnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lba, lu_cmd->lblen); +error_return: + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr); + lu_task->complete_queue_ptr = NULL; + MTX_UNLOCK(&spec->complete_queue_mutex); +error_return_no_dequeue: + rc = istgt_lu_destroy_task(lu_task); + if (rc < 0) { + ISTGT_ERRLOG("lu_destroy_task() failed\n"); + return -1; + } +/* should we send error back to client? */ + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "LU%d: Queue%s (%s)(q:%d/%d %d) CmdSN=%u,0x%x.%lu+%u\n", + lu->num, qact[sindx < 0 || sindx > 6 ? 7 : sindx], msg, ccnt, bcnt, icnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lba, lu_cmd->lblen); + + /* notify LUN thread */ + if(!is_maintenance_io(lu_task)) + { + if(spec->schdler_cmd_waiting) { + clock_gettime(clockid, &sch1); + rc = pthread_cond_signal(&spec->cmd_queue_cond); + if (rc != 0) { +/* We are not removing from the cmd/blocked qeuue */ + ISTGT_ERRLOG("LU%d: cond_broadcast() failed rc = %d\n errno = %d", lu->num, rc, errno); + goto error_return; + } + clock_gettime(clockid, &sch2); + id = 20; + ttdiff(sch1, sch2, r); + } + } + else + { + rc = pthread_cond_signal(&spec->maint_cmd_queue_cond); + if (rc != 0) { +/* We are not removing from the maint cmd/blocked qeuue */ + ISTGT_ERRLOG("LU%d: cond_broadcast() failed rc = %d\n errno = %d", lu->num, rc, errno); + goto error_return; + } + } + MTX_UNLOCK(&spec->complete_queue_mutex); + + return ISTGT_LU_TASK_RESULT_QUEUE_OK; +} +/* +int +istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu, int *lun) +{ + ISTGT_LU_DISK *spec; + int qcnt; + int bqcnt; + int luns; + int i; + + if (lun == NULL) + return -1; + + i = *lun; + if (i >= lu->maxlun) { + *lun = 0; + i = 0; + } + + qcnt = 0; + bqcnt = 0; + for (luns = lu->maxlun; luns >= 0 ; luns--) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + goto next_lun; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + goto next_lun; + } + spec = (ISTGT_LU_DISK *) lu->lun[i].spec; + if (spec == NULL) { + goto next_lun; + } + + MTX_LOCK(&spec->cmd_queue_mutex); + qcnt = istgt_queue_count(&spec->cmd_queue); + bqcnt = istgt_queue_count(&spec->blocked_queue); + MTX_UNLOCK(&spec->cmd_queue_mutex); + + if (qcnt+bqcnt > 0) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "LU%d: LUN%d queue(%d) bqueue(%d)\n", + lu->num, i, qcnt,bqcnt); + *lun = spec->lun; + break; + } + + next_lun: + i++; + if (i >= lu->maxlun) { + i = 0; + } + } + return qcnt+bqcnt; +} +*/ +/* +int +istgt_lu_disk_cmd_queue_count(ISTGT_LU_Ptr lu, int *lun) +{ + ISTGT_LU_DISK *spec = NULL; + int qcnt; + int luns; + int i; + + if (lun == NULL) + return -1; + + i = *lun; + if (i >= lu->maxlun) { + *lun = 0; + i = 0; + } + + qcnt = 0; + for (luns = lu->maxlun; luns >= 0 ; luns--) { + if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) { + goto next_lun; + } + if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) { + ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num); + goto next_lun; + } + spec = (ISTGT_LU_DISK *) lu->lun[i].spec; + if (spec == NULL) { + goto next_lun; + } + + MTX_LOCK(&spec->cmd_queue_mutex); + qcnt = istgt_queue_count(&spec->cmd_queue); + MTX_UNLOCK(&spec->cmd_queue_mutex); + + if (qcnt > 0) { + *lun = spec->lun; + break; + } + + next_lun: + i++; + if (i >= lu->maxlun) { + i = 0; + } + } + return qcnt; +} +*/ +#define INFLIGHT_IO_CLEANUP \ + {\ + MTX_LOCK(&spec->luworker_mutex[worker_id]);\ + MTX_LOCK(&spec->lu_tmf_mutex[worker_id]);\ + if(spec->lu_tmf_wait[worker_id] == 1)\ + {\ + spec->lu_tmf_wait[worker_id] = 0;\ + rc = pthread_cond_signal(&spec->lu_tmf_cond[worker_id]);\ + if(rc != 0) {\ + ISTGT_ERRLOG("signalling failed\n");\ + }\ + }\ + MTX_UNLOCK(&spec->lu_tmf_mutex[worker_id]);\ + if(likely(lu_task != NULL)) {\ + if((lu_task->lu_cmd).aborted == 1) {\ + ISTGT_LOG("CmdSN %d aborted in inflight", (lu_task->lu_cmd).CmdSN);\ + aborted = 1;\ + }\ + if(likely(spec->inflight_io[worker_id] == lu_task))\ + {\ + lu_task->lu_cmd.flags |= ISTGT_COMPLETED_EXEC;\ + spec->inflight_io[worker_id] = NULL;\ + if(likely(lu_task != NULL))\ + decrement_conn_inflight = 1;\ + }\ + else {\ + spec->error_count++;\ + ISTGT_ERRLOG("LU%d: Error thread %d: Inflight IO overwrite!!! \n", lu->num, worker_id);\ + }\ + }\ + if(unlikely(worker_id >= spec->luworkers))\ + {\ + MTX_UNLOCK(&spec->luworker_mutex[worker_id]);\ + }\ + else\ + {\ + MTX_LOCK(&spec->schdler_mutex);\ + if(in_lu_worker_exit == 0)\ + BSET32(spec->lu_free_matrix[(worker_id >> 5)], (worker_id & 31));\ + spec->inflight--;\ + if(spec->schdler_waiting) {\ + MTX_UNLOCK(&spec->schdler_mutex);\ + MTX_UNLOCK(&spec->luworker_mutex[worker_id]);\ + pthread_cond_signal(&spec->schdler_cond);\ + } else {\ + MTX_UNLOCK(&spec->schdler_mutex);\ + MTX_UNLOCK(&spec->luworker_mutex[worker_id]);\ + }\ + }\ +/* No need to wake up maint_thread as there is only thread and it is looping */\ + if(likely(lu_task != NULL)) {\ + MTX_LOCK(&spec->complete_queue_mutex);\ + istgt_queue_dequeue_middle(&spec->complete_queue, lu_task->complete_queue_ptr);\ + lu_task->complete_queue_ptr = NULL;\ + if(likely(decrement_conn_inflight == 1))\ + {\ + lu_task->conn->inflight--;\ + decrement_conn_inflight = 0;\ + }\ + }\ + if(spec->schdler_cmd_waiting == 1)\ + {\ + MTX_UNLOCK(&spec->complete_queue_mutex);\ + pthread_cond_signal(&spec->cmd_queue_cond);\ + }\ + else\ + {\ + MTX_UNLOCK(&spec->complete_queue_mutex);\ + }\ + } + +void luworker_exit(void *void_arg); + +void luworker_exit(void *void_arg) +{ + struct luworker_exit_args *arg = (struct luworker_exit_args *)void_arg; + ISTGT_LU_DISK *spec = arg->spec; + int worker_id = arg->workerid; + ISTGT_LU_TASK_Ptr lu_task = arg->lu_task; + ISTGT_LU_Ptr lu = spec->lu; + int decrement_conn_inflight = 0; + int rc; + int aborted = 0; + int in_lu_worker_exit = 1; + + INFLIGHT_IO_CLEANUP; + ISTGT_WARNLOG("luworker:%p %d thread_exit ios_aborted:%d\n", spec, worker_id, aborted); + + return; +} + +int +istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu, int lun, int worker_id) +{ + ISTGT_QUEUE_Ptr r_ptr = NULL; + ISTGT_LU_DISK *spec = NULL; + ISTGT_LU_TASK_Ptr lu_task; + CONN_Ptr conn; + ISTGT_LU_CMD_Ptr lu_cmd; + struct timespec abstime; + time_t start, now; + int rc, i, timed_wait_rc = 0; + uint32_t CmdSN; + int opcode, printmsg = 1, aborted = 0; + const char *msg = ""; + int decrement_conn_inflight = 0; + int retval = -1; + int in_lu_worker_exit = 0; + + if (lun < 0 || lun >= lu->maxlun) { + return -1; + } + + spec = (ISTGT_LU_DISK *) lu->lun[lun].spec; + if (spec == NULL) + { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue start: returning, storage unavailable\n", + lu->num, lun); + return -1; + } + + MTX_LOCK(&spec->luworker_mutex[worker_id]); + lu_task = spec->inflight_io[worker_id]; + MTX_UNLOCK(&spec->luworker_mutex[worker_id]); + if(lu_task == NULL) + { + INFLIGHT_IO_CLEANUP; + return 0; + } + + spec->luworker_exit_arg[worker_id].spec = spec; + spec->luworker_exit_arg[worker_id].workerid = worker_id; + spec->luworker_exit_arg[worker_id].lu_task = lu_task; + + pthread_cleanup_push(luworker_exit, &(spec->luworker_exit_arg[worker_id])); + lu_task->thread = pthread_self(); + conn = lu_task->conn; + lu_cmd = &lu_task->lu_cmd; + timediffw(lu_cmd, 'q'); + + CmdSN = lu_cmd->CmdSN; + opcode = lu_cmd->cdb[0]; + + if(spec->exit_lu_worker) + { + MTX_LOCK(&conn->result_queue_mutex); + if(spec->exit_lu_worker) + { + spec->exit_lu_worker = 0; + MTX_UNLOCK(&conn->result_queue_mutex); + pthread_exit(NULL); + } + MTX_UNLOCK(&conn->result_queue_mutex); + } + + if (lu_cmd->W_bit) { + if (lu_cmd->pdu->data_segment_len >= lu_cmd->transfer_len) { + i = ++lu_cmd->iobufindx; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d LU%d: CSN:0x%x LUN%d Task Write Immediate Start, op:0x%x [%d,%lu->%lu]\n", + conn->id, lu->num, CmdSN, lun, opcode, + i, lu_cmd->iobuf[i].iov_len, lu_cmd->pdu->data_segment_len); + lu_cmd->iobuf[i].iov_base = lu_cmd->pdu->data; + lu_cmd->iobuf[i].iov_len = lu_cmd->pdu->data_segment_len; + lu_cmd->iobufsize = lu_cmd->pdu->data_segment_len; + lu_cmd->pdu->data = NULL; lu_cmd->pdu->data_segment_len = 0; + lu_task->dup_iobuf = 1; + + //MTX_LOCK(&lu_cmd->lu->mutex); + rc = istgt_lu_disk_execute(conn, lu_cmd); + //MTX_UNLOCK(&lu_cmd->lu->mutex); + + if ((rc < 0) || (lu_cmd->connGone == 1)) { + if(lu_cmd->connGone == 1) + msg = "lu_disk_execute2 failed Error:connGone"; + else + msg = "lu_disk_execute1 failed"; + goto error_return; + } + lu_task->execute = 1; + + /* response */ + MTX_LOCK(&conn->result_queue_mutex); + INFLIGHT_IO_CLEANUP; + if(aborted == 1) + { + MTX_UNLOCK(&conn->result_queue_mutex); + goto error_return_no_cleanup; + } + r_ptr = istgt_queue_enqueue(&conn->result_queue, lu_task); + if (r_ptr == NULL) { + MTX_UNLOCK(&conn->result_queue_mutex); + msg = "rsltq1 failed"; + goto error_return_no_cleanup; + } + lu_task->lu_cmd.flags |= ISTGT_RESULT_Q_ENQUEUED; + rc = 0; + if(conn->sender_waiting == 1) + rc = pthread_cond_signal(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + if (rc != 0) { + msg = "rsltq1 bcast failed"; + goto error_return_no_destroy; + } + + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "c#%d LU%d: CSN:0x%x LUN%d Task Write Start, op:0x%x\n", + conn->id, lu->num, CmdSN, lun, opcode); + +#if 0 + MTX_LOCK(&spec->wait_lu_task_mutex); + spec->wait_lu_task = NULL; + MTX_UNLOCK(&spec->wait_lu_task_mutex); +#endif + rc = pthread_mutex_init(&lu_task->trans_mutex, NULL); + if (rc != 0) { + msg = "mtx2 failed"; + goto error_return; + } + rc = pthread_cond_init(&lu_task->trans_cond, NULL); + if (rc != 0) { + msg = "cond2 failed"; + goto error_return; + } + rc = pthread_cond_init(&lu_task->exec_cond, NULL); + if (rc != 0) { + msg = "cond2a failed"; + goto error_return; + } + lu_task->use_cond = 1; + + //lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize; + //lu_cmd->iobuf = lu_task->iobuf; + + lu_task->req_transfer_out = 1; + abstime.tv_sec = 0; + abstime.tv_nsec = 0; + + MTX_LOCK(&conn->task_queue_mutex); + r_ptr = istgt_queue_enqueue(&conn->task_queue, lu_task); + MTX_UNLOCK(&conn->task_queue_mutex); + if (r_ptr == NULL) { + msg = "tskq enqueue failed"; + goto error_return; + } + rc = write(conn->task_pipe[1], "Q", 1); //something other than E + if(rc < 0 || rc != 1) { + msg = "tskpipe write failed"; + INFLIGHT_IO_CLEANUP; + //Should we dequeue enqueued task? + goto error_return_no_destroy; + } + if(spec->error_inject & R2T_TASK_BEFORE_WAIT) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + + start = now = time(NULL); + abstime.tv_sec = now + lu_task->condwait; // / 1000); + abstime.tv_nsec = 0; //(lu_task->condwait % 1000) * 1000000; + + MTX_LOCK(&spec->wait_lu_task_mutex); + spec->wait_lu_task[worker_id] = lu_task; + MTX_UNLOCK(&spec->wait_lu_task_mutex); + MTX_LOCK(&lu_task->trans_mutex); + rc = 0; + while (lu_task->req_transfer_out == 1) { + rc = pthread_cond_timedwait(&lu_task->trans_cond, + &lu_task->trans_mutex, + &abstime); + if(spec->error_inject & R2T_TASK_AFTER_WAIT) + if(spec->inject_cnt > 0) + { + spec->inject_cnt--; + sleep(8); + } + if (rc == ETIMEDOUT) { + if (lu_task->req_transfer_out == 1) { + INFLIGHT_IO_CLEANUP; + lu_task->error = 1; + lu_task->lu_cmd.aborted = 1; + MTX_LOCK(&spec->wait_lu_task_mutex); + spec->wait_lu_task[worker_id] = NULL; + MTX_UNLOCK(&spec->wait_lu_task_mutex); + MTX_UNLOCK(&lu_task->trans_mutex); + + now = time(NULL); + ISTGT_ERRLOG("c#%d timeout trans_cond CmdSN=0x%x " + "(time=%f)\n", + conn->id, lu_task->lu_cmd.CmdSN, + difftime(now, start)); + /* timeout */ + goto return_retval; + } + /* OK cond */ + if (lu_task->error == 0) + rc = 0; + else { + lu_task->lu_cmd.aborted = 1; + rc = -1; + } + break; + } + if (lu_task->error != 0) { + rc = -1; + lu_task->lu_cmd.aborted = 1; + break; + } + if (rc != 0) { + break; + } + } + MTX_UNLOCK(&lu_task->trans_mutex); + + MTX_LOCK(&spec->wait_lu_task_mutex); + spec->wait_lu_task[worker_id] = NULL; + MTX_UNLOCK(&spec->wait_lu_task_mutex); + + if (rc != 0) { + lu_task->lu_cmd.aborted = 1; + timed_wait_rc = rc; + INFLIGHT_IO_CLEANUP; //This modifies rc + rc = timed_wait_rc; + if (rc < 0) { + lu_task->error = 1; + if (lu_task->abort) { + ISTGT_WARNLOG("c#%d transfer abort CmdSN=0x%x\n", + conn->id, lu_task->lu_cmd.CmdSN); + //destroy lu_task? + retval = -2; + goto return_retval; + } else { + ISTGT_ERRLOG("c#%d transfer error CmdSN=0x%x\n", + conn->id, lu_task->lu_cmd.CmdSN); + //destroy lu_task? + goto return_retval; + } + } + if (rc == ETIMEDOUT) { + lu_task->error = 1; + now = time(NULL); + //timedout tasks should not be deleted + ISTGT_ERRLOG("c#%d timeout trans_cond CmdSN=0x%x (time=%f)\n", + conn->id, lu_task->lu_cmd.CmdSN, difftime(now, start)); + goto return_retval; + } + lu_task->error = 1; + //destroy lu_task? + ISTGT_ERRLOG("c#%d cond_timedwait rc=%d\n",conn->id, rc); + goto return_retval; + } + + if (lu_task->req_execute == 0) { + msg = "wrong request!"; + goto error_return; + } + //MTX_LOCK(&lu_cmd->lu->mutex); + rc = istgt_lu_disk_execute(conn, lu_cmd); + //MTX_UNLOCK(&lu_cmd->lu->mutex); + + if ((rc < 0) || (lu_cmd->connGone == 1)) { + lu_task->error = 1; + if(lu_cmd->connGone == 1) + msg = "lu_disk_execute2 failed Error:connGone"; + else + msg = "lu_disk_execute2 failed"; + goto error_return; + } + lu_task->execute = 1; + + /* response */ + MTX_LOCK(&conn->result_queue_mutex); + INFLIGHT_IO_CLEANUP; + if(aborted == 1) + { + MTX_UNLOCK(&conn->result_queue_mutex); + goto error_return_no_cleanup; + } + r_ptr = istgt_queue_enqueue(&conn->result_queue, lu_task); + if (r_ptr == NULL) { + MTX_UNLOCK(&conn->result_queue_mutex); + msg = "rsltq2 failed"; + goto error_return_no_cleanup; + } + lu_task->lu_cmd.flags |= ISTGT_RESULT_Q_ENQUEUED; + rc = 0; + if(conn->sender_waiting == 1) + rc = pthread_cond_signal(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + if (rc != 0) { + msg = "rsltq2 bcast failed"; + goto error_return_no_destroy; + } + } + } else { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "c#%d LU%d: CSN:%x LUN%d Task Read Start, op:0x%x\n", + conn->id, lu->num, CmdSN, lun, opcode); + + //lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize; + //lu_cmd->iobuf = lu_task->iobuf; + + //MTX_LOCK(&lu_cmd->lu->mutex); + rc = istgt_lu_disk_execute(conn, lu_cmd); + //MTX_UNLOCK(&lu_cmd->lu->mutex); + + if ((rc < 0) || (lu_cmd->connGone == 1)) { + if(lu_cmd->connGone == 1) + msg = "lu_disk_execute2 failed Error:connGone"; + else + msg = "lu_disk_execute3 failed"; + goto error_return; + } + lu_task->execute = 1; + + /* response */ + MTX_LOCK(&conn->result_queue_mutex); + INFLIGHT_IO_CLEANUP; + if(aborted == 1) + { + MTX_UNLOCK(&conn->result_queue_mutex); + goto error_return_no_cleanup; + } + r_ptr = istgt_queue_enqueue(&conn->result_queue, lu_task); + if (r_ptr == NULL) { + MTX_UNLOCK(&conn->result_queue_mutex); + msg = "rsltq3 failed"; + goto error_return_no_cleanup; + } + lu_task->lu_cmd.flags |= ISTGT_RESULT_Q_ENQUEUED; + rc = 0; + if(conn->sender_waiting == 1) + rc = pthread_cond_signal(&conn->result_queue_cond); + MTX_UNLOCK(&conn->result_queue_mutex); + if (rc != 0) { + msg = "rsltq3 bcast failed"; + goto error_return_no_destroy; + } + } + retval = 0; + goto return_retval; + +error_return: + INFLIGHT_IO_CLEANUP; +error_return_no_cleanup: + if (lu_cmd && conn && lu_cmd->connGone == 1) { + ISTGT_ERRLOG("c#%d LU%d: LUN%d connGone set, error:%s, op:0x%x cmdSN:0x%x (ret:%d)\n", + conn->id, lu->num, lun, msg, opcode, CmdSN, rc); + printmsg = 0; + } + istgt_lu_destroy_task(lu_task); + +error_return_no_destroy: + if (printmsg == 1) { + ISTGT_ERRLOG("c#%d LU%d: LUN%d error:%s, op:0x%x cmdSN:0x%x (ret:%d)\n", + conn->id, lu->num, lun, msg, opcode, CmdSN, rc); + } +return_retval: + ; + pthread_cleanup_pop(0); + return retval; +} + +int +istgt_lu_disk_busy_excused(int opcode) +{ + int ret = 0; + switch(opcode) { + case SPC_INQUIRY: + case SPC_TEST_UNIT_READY: + case SPC_MODE_SENSE_10: + case SPC_REQUEST_SENSE: + //case SPC2_RESERVE_6: + case SPC_REPORT_LUNS : + case SBC_READ_CAPACITY_10: + case SCC_MAINTENANCE_IN: + ret =1; + break; + default: + break; + } + return ret; + +} +#define checklength \ + if(transfer_len*spec->blocklen > (uint64_t)lu->MaxBurstLength) { \ + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; \ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);\ + break;\ + } + +int +istgt_lu_disk_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_LU_Ptr lu; + ISTGT_LU_DISK *spec; + IT_NEXUS *nexus; + istgt_ua_type ua_pending; + uint8_t *data = NULL; + int freedata = 0; + uint8_t *cdb; + uint32_t allocation_len; + int data_len; + int data_alloc_len = 1024*1024*1; + int max_alloc_size = 1024*1024*1; + uint64_t lba; + uint32_t len; + uint32_t transfer_len; + uint32_t parameter_len; + int lun_i; + int rc = 0; + int lunum, dolog = 0; + const char *msg = ""; + uint64_t *tptr; + int sa= 0; + if (lu_cmd == NULL) + return -1; + lu = lu_cmd->lu; + if (lu == NULL) { + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + lunum = lu->num; + spec = NULL; + cdb = lu_cmd->cdb; + errno = 0; + + lu_cmd->flags |= ISTGT_DISK_EXEC; + + lun_i = istgt_lu_islun2lun(lu_cmd->lun); + if (lun_i >= lu->maxlun) { + if (cdb[0] == SPC_INQUIRY) { + allocation_len = DGET16(&cdb[3]); + data_len = 96; + data = lu_cmd->data = xmalloc(data_len + 200); + memset(data, 0, data_len+200); + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + BDSET8W(&data[0], 0x03, 7, 3); + BDADD8W(&data[0], 0x1f, 4, 5); + memset(&data[1], 0, data_len - 1); + /* ADDITIONAL LENGTH */ + data[4] = data_len - 5; + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; +/* + ISTGT_ERRLOG("LU%d: LUN%4.4d invalid\n", lu->num, lun_i); +*/ + return 0; + } else { + /* LOGICAL UNIT NOT SUPPORTED */ + ISTGT_ERRLOG("c#%d Illegal_Request, lun_i %d maxlun %d\n",conn->id, lun_i, lu->maxlun); + BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return 0; + } + } + spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec; + if (spec == NULL) { + /* LOGICAL UNIT NOT SUPPORTED */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return 0; + } + + MTX_LOCK(&spec->state_mutex); + if (spec->state == ISTGT_LUN_BUSY && (!istgt_lu_disk_busy_excused(cdb[0]))) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + MTX_UNLOCK(&spec->state_mutex); + MTX_LOCK(&spec->sleep_mutex); + sleep(1); + MTX_UNLOCK(&spec->sleep_mutex); + return 0; + } + MTX_UNLOCK(&spec->state_mutex); + + { + int sk =0 , asc = 0, ascq = 0; + if (spec->sense != 0) { + if (cdb[0] != SPC_INQUIRY + && cdb[0] != SPC_REPORT_LUNS) { + sk = (spec->sense >> 16) & 0xffU; + asc = (spec->sense >> 8) & 0xffU; + ascq = (spec->sense >> 0) & 0xffU; + spec->sense = 0; + rc = 1; + goto return_sense; + } + } + + nexus = istgt_lu_disk_get_nexus(spec, conn->initiator_port); + if (nexus != NULL) { + MTX_LOCK(&nexus->nexus_mutex); + ua_pending = nexus->ua_pending; + if (ua_pending != ISTGT_UA_NONE) { + /* Send priority UA */ + ua_pending = istgt_lu_disk_build_ua(ua_pending, &sk, &asc, &ascq); + if (ua_pending != ISTGT_UA_NONE) { + rc = 1; + nexus->ua_pending &= ~ua_pending; + MTX_UNLOCK(&nexus->nexus_mutex); + goto return_sense; + } + } + MTX_UNLOCK(&nexus->nexus_mutex); + } + + return_sense: + if (rc){ + ISTGT_LOG( "c#%d Generate sk=0x%x, asc=0x%x, ascq=0x%x\n", conn->id, sk, asc, ascq); + istgt_lu_scsi_build_sense_data(lu_cmd, sk, asc, ascq); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return 0; + } + } + + + //ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + // "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n", + // cdb[0], lu_cmd->lun); +#if 0 //ISTGT_TRACE_DISK + if (cdb[0] != SPC_TEST_UNIT_READY) { + istgt_scsi_dump_cdb(cdb); + } +#endif /* ISTGT_TRACE_DISK */ + + switch (cdb[0]) { + case SPC_INQUIRY: + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d INQUIRY R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + allocation_len = DGET16(&cdb[3]); + data_alloc_len = allocation_len + 2048; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + data_len = istgt_lu_disk_scsi_inquiry(spec, conn, cdb, + data, data_alloc_len); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d INQUIRY error:%d\n", conn->id, data_len); + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d INQUIRY mem-error:%d-%d\n", conn->id, data_len, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len); + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + + case SPC_REPORT_LUNS: + { + int sel; + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d REPORT_LUNS R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + sel = cdb[2]; + allocation_len = DGET32(&cdb[6]); + data_alloc_len = allocation_len + 2048; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + if (allocation_len < 16) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + data_len = istgt_lu_disk_scsi_report_luns(lu, conn, cdb, sel, + data, data_alloc_len); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else { + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + } + break; + } + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len); + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d REPORT_LUNS sel:%x len:%lu (%d/%u/%u)\n", + conn->id, sel, lu_cmd->data_len, data_len, lu_cmd->transfer_len, allocation_len); + } + break; + + case SPC_TEST_UNIT_READY: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d TEST_UNIT_READY\n", conn->id); + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + + case SBC_START_STOP_UNIT: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d START_STOP_UNIT\n", conn->id); + { + int pc, start; + + pc = BGET8W(&cdb[4], 7, 4); + start = BGET8(&cdb[4], 0); + + if (start != 0 || pc != 0) { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, + PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status + = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + } + + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + } + break; + + case SBC_READ_CAPACITY_10: + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d READ_CAPACITY_10 R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(200); + if (spec->blockcnt - 1 > 0xffffffffULL) { + DSET32(&data[0], 0xffffffffUL); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ_CAPACITY_10 blklen:%lu\n", conn->id, spec->blocklen); + } else { + DSET32(&data[0], (uint32_t) (spec->blockcnt - 1)); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ_CAPACITY_10 blkcnt:%lu blklen:%lu\n", conn->id, spec->blockcnt, spec->blocklen); + } + DSET32(&data[4], (uint32_t) spec->blocklen); + tptr = (uint64_t *)&(data[8]); + *tptr = 0; *(tptr+1) = 0; + data_len = 8; + lu_cmd->data_len = data_len; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "SBC_READ_CAPACITY_10", data, data_len); + break; + + case SPC_SERVICE_ACTION_IN_16: + sa = BGET8W(&cdb[1], 4, 5); /* SERVICE ACTION */ + switch (sa) { + case SBC_SAI_READ_CAPACITY_16: + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d READ_CAPACITY_16 R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + allocation_len = DGET32(&cdb[10]); + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d READ_CAPACITY_16 data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d READ_CAPACITY_16 blkcnt:%lu blklen:%lu rshift:%u/%u %s\n", + conn->id, spec->blockcnt, spec->blocklen, spec->rshift, spec->rshiftreal, spec->unmap ? "thin" : "-"); + + data_len = 32; + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + data = lu_cmd->data = xmalloc(data_len + 20); + memset(data, 0, data_len+20); + DSET64(&data[0], spec->blockcnt - 1); + DSET32(&data[8], (uint32_t) spec->blocklen); + data[12] = 0; /* RTO_EN(1) PROT_EN(0) */ + data[13] = 0; + data[13] = spec->rshift & 0x0f; + //if (spec->rshift > 0) + // BDSET8W(&data[13], spec->rshift, 3, 4); + if (spec->unmap) + data[14] = 0x80; + else + data[14] = 0; + data[15] = 0; + tptr = (uint64_t *)(&(data[16])); + *tptr = 0; *(tptr+1) = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + case SBC_SAI_READ_LONG_16: + default: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d SA_IN_16:op:0x%2.2x unhandled\n", conn->id, sa); + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + break; + + case SPC_MODE_SELECT_6: +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + { + int pf, sp, pllen; + int bdlen; + + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + pf = BGET8(&cdb[1], 4); + sp = BGET8(&cdb[1], 0); + pllen = cdb[4]; /* Parameter List Length */ + + if (pllen == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, pllen); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (pllen < 4) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } +#if 0 + istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen); +#endif + getdata(data, lu_cmd) + bdlen = data[3]; /* Block Descriptor Length */ + + /* Short LBA mode parameter block descriptor */ + /* data[4]-data[7] Number of Blocks */ + /* data[8]-data[11] Block Length */ + + /* page data */ + data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen)); + if (data_len != 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = pllen; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SPC_MODE_SELECT_10: +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + { + int pf, sp, pllen; + int bdlen; + int llba; + + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + pf = BGET8(&cdb[1], 4); + sp = BGET8(&cdb[1], 0); + pllen = DGET16(&cdb[7]); /* Parameter List Length */ + + if (pllen == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, pllen); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (pllen < 4) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } +#if 0 + istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen); +#endif + getdata(data, lu_cmd) //data = lu_cmd->iobuf; + llba = BGET8(&data[4], 0); /* Long LBA */ + bdlen = DGET16(&data[6]); /* Block Descriptor Length */ + + if (llba) { + /* Long LBA mode parameter block descriptor */ + /* data[8]-data[15] Number of Blocks */ + /* data[16]-data[19] Reserved */ + /* data[20]-data[23] Block Length */ + } else { + /* Short LBA mode parameter block descriptor */ + /* data[8]-data[11] Number of Blocks */ + /* data[12]-data[15] Block Length */ + } + + /* page data */ + data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen)); + if (data_len != 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = pllen; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SPC_MODE_SENSE_6: +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + { + int dbd, pc, page, subpage; + + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("R_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + dbd = BGET8(&cdb[1], 3); + pc = BGET8W(&cdb[2], 7, 2); + page = BGET8W(&cdb[2], 5, 6); + subpage = cdb[3]; + + allocation_len = cdb[4]; + data_alloc_len = allocation_len + 2048; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, data_alloc_len); + data_len = istgt_lu_disk_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len); + if (data_len < 0) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d MODE SENSE6 dbd:%x pc:%x page:%x subpage:%x alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, dbd, pc, page, subpage, + allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } +#if 0 + istgt_dump("MODE SENSE(6)", data, data_len); +#endif + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MODE SENSE6 dbd:%x pc:%x page:%x subpage:%x alen:%d dlen:%d tlen:%d", + conn->id, dbd, pc, page, subpage, + allocation_len, data_len, lu_cmd->transfer_len); + + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SPC_MODE_SENSE_10: +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + { + int dbd, pc, page, subpage; + int llbaa; + + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + llbaa = BGET8(&cdb[1], 4); + dbd = BGET8(&cdb[1], 3); + pc = BGET8W(&cdb[2], 7, 2); + page = BGET8W(&cdb[2], 5, 6); + subpage = cdb[3]; + + allocation_len = DGET16(&cdb[7]); + data_alloc_len = allocation_len + 2048; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, data_alloc_len); + + data_len = istgt_lu_disk_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len); + if (data_len < 0) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d MODE SENSE10 dbd:%x pc:%x page:%x subpage:%x alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, dbd, pc, page, subpage, + allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + +#if 0 + istgt_dump("MODE SENSE(10)", data, data_len); +#endif + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + ISTGT_NOTICELOG("c#%d MODE SENSE10 dbd:%x pc:%x page:%x subpage:%x alen:%d dlen:%d tlen:%d", + conn->id, dbd, pc, page, subpage, + allocation_len, data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SPC_LOG_SELECT: + { + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + } + case SPC_LOG_SENSE: + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + + case SPC_REQUEST_SENSE: + { + int desc; + int sk, asc, ascq; + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + desc = BGET8(&cdb[1], 0); + if (desc != 0) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + allocation_len = cdb[4]; + data_alloc_len = allocation_len + 2048; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + + if (!spec->sense) { + /* NO ADDITIONAL SENSE INFORMATION */ + sk = ISTGT_SCSI_SENSE_NO_SENSE; + asc = 0x00; + ascq = 0x00; + } else { + sk = (spec->sense >> 16) & 0xffU; + asc = (spec->sense >> 8) & 0xffU; + ascq = spec->sense & 0xffU; + } + istgt_lu_scsi_build_sense_data(lu_cmd, sk, asc, ascq); + data_len = lu_cmd->sense_data_len; + if (data_len < 0 || data_len < 2) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + /* omit SenseLength */ + data_len -= 2; + memcpy(data, lu_cmd->sense_data + 2, data_len); +#if 0 + istgt_dump("REQUEST SENSE", data, data_len); +#endif + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + if (lu_cmd->data_len > (size_t)data_len) + memset(data+data_len, 0, lu_cmd->data_len - data_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SPC_RECEIVE_COPY_RESULTS: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + allocation_len = DGET32(&cdb[10]); + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + if (allocation_len == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + data_len = istgt_lu_disk_receive_copy_results(conn, lu_cmd); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + ISTGT_ERRLOG("c#%d lu_disk_receive_copy_results() failed\n", conn->id); + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_6: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("R_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU); + transfer_len = (uint32_t) DGET8(&cdb[4]); + if (transfer_len == 0) { + transfer_len = 256; + } + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d READ_6(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbread() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_10: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d READ_10(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbread() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_12: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("R_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[6]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d READ_12(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbread() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_16: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d READ_16(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbread() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_6: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU); + transfer_len = (uint32_t) DGET8(&cdb[4]); + if (transfer_len == 0) { + transfer_len = 256; + } + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_6(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbwrite() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_10: + case SBC_WRITE_AND_VERIFY_10: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_10(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbwrite() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_12: + case SBC_WRITE_AND_VERIFY_12: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[6]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_12(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbwrite() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_16: + case SBC_WRITE_AND_VERIFY_16: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + checklength; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_16(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbwrite() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_VERIFY_10: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET16(&cdb[7]); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d VERIFY_10(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, len); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_VERIFY_12: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET32(&cdb[6]); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d VERIFY_12(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, len); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_VERIFY_16: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + lba = (uint64_t) DGET64(&cdb[2]); + len = (uint32_t) DGET32(&cdb[10]); + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d VERIFY_16(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, len); + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_SAME_10: + { + int pbdata, lbdata; + + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET32(&cdb[2]); + transfer_len = (uint32_t) DGET16(&cdb[7]); + checklength; + //group_no = BGET8W(&cdb[6], 4, 5) + /* only PBDATA=0 and LBDATA=0 support */ + if (pbdata || lbdata) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_SAME_10(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbwrite_same() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_WRITE_SAME_16: + { + int anchor, unmap, pbdata, lbdata; + +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + anchor = BGET8(&cdb[1], 4); + unmap = BGET8(&cdb[1], 3); + pbdata = BGET8(&cdb[1], 2); + lbdata = BGET8(&cdb[1], 1); + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET32(&cdb[10]); + checklength; + //group_no = BGET8W(&cdb[14], 4, 5); + /* only PBDATA=0 and LBDATA=0 support */ + if (pbdata || lbdata) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (anchor) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d WRITE_SAME_16(lba %"PRIu64", len %u blocks) %s\n", + conn->id, lba, transfer_len, unmap ? "UNMAP bit" : " "); + rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d WRITE_SAME_16(lba %"PRIu64", len %u blocks) failed. %s\n", + conn->id, lba, transfer_len, unmap ? "UNMAP bit" : " "); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_COMPARE_AND_WRITE: + { + int64_t maxlen; +#if 0 + istgt_scsi_dump_cdb(cdb); +#endif + if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) { + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("W_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + lba = (uint64_t) DGET64(&cdb[2]); + transfer_len = (uint32_t) DGET8(&cdb[13]); + + maxlen = ISTGT_LU_WORK_ATS_BLOCK_SIZE / spec->blocklen; + if (maxlen > 0xff) { + maxlen = 0xff; + } + if (transfer_len > maxlen) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d COMPARE_AND_WRITE(lba %"PRIu64", len %u blocks)\n", + conn->id, lba, transfer_len); + rc = istgt_lu_disk_lbwrite_ats(spec, conn, lu_cmd, lba, transfer_len); + if (rc < 0) { + //ISTGT_ERRLOG("lu_disk_lbwrite_ats() failed\n"); + /* sense data build by function */ + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_SYNCHRONIZE_CACHE_10: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + lba = (uint64_t) DGET32(&cdb[2]); + len = (uint32_t) DGET16(&cdb[7]); + if (len == 0) { + len = spec->blockcnt; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d SYNCHRONIZE_CACHE_10(lba %"PRIu64 + ", len %u blocks)\n", + conn->id, lba, len); + rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbsync() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_SYNCHRONIZE_CACHE_16: + { + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + + lba = (uint64_t) DGET64(&cdb[2]); + len = (uint32_t) DGET32(&cdb[10]); + if (len == 0) { + len = spec->blockcnt; + } + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, + "c#%d SYNCHRONIZE_CACHE_10(lba %"PRIu64 + ", len %u blocks)\n", + conn->id, lba, len); + rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbsync() failed\n", conn->id); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_DEFECT_DATA_10: + { + int req_plist, req_glist, list_format; + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + req_plist = BGET8(&cdb[2], 4); + req_glist = BGET8(&cdb[2], 3); + list_format = BGET8W(&cdb[2], 2, 3); + + allocation_len = (uint32_t) DGET16(&cdb[7]); + data_alloc_len = allocation_len + 8192; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + + data_len = istgt_lu_disk_scsi_read_defect10(spec, conn, cdb, + req_plist, req_glist, list_format, data, data_alloc_len); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d READ_DEFECT_DATA10 alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SBC_READ_DEFECT_DATA_12: + { + int req_plist, req_glist, list_format; + + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d R_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + req_plist = BGET8(&cdb[2], 4); + req_glist = BGET8(&cdb[2], 3); + list_format = BGET8W(&cdb[2], 2, 3); + + allocation_len = DGET32(&cdb[6]); + data_alloc_len = allocation_len + 8192; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + + data_len = istgt_lu_disk_scsi_read_defect12(spec, conn, cdb, + req_plist, req_glist, list_format, data, data_alloc_len); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d READ_DEFECT_DATA12 alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + case SCC_MAINTENANCE_IN: + sa = BGET8W(&cdb[1], 4, 5); /* SERVICE ACTION */ + switch (sa) { /* SERVICE ACTION */ + case SPC_MI_REPORT_TARGET_PORT_GROUPS: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MAINTENANCE_IN: sa:0x%2.2x:REPORT_TARGET_PORT_GROUPS\n", conn->id, sa); + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("R_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + allocation_len = DGET32(&cdb[6]); + data_alloc_len = allocation_len + 8192; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + data_len = istgt_lu_disk_scsi_report_target_port_groups(spec, conn, cdb, data, data_alloc_len); + if (data_len < 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d REPORT_TPGs alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "REPORT_TARGET_PORT_GROUPS", data, data_len); + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + default: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MAINTENANCE_IN: sa:0x%2.2x:unhandled\n", conn->id, sa); + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + break; + + case SCC_MAINTENANCE_OUT: + sa = BGET8W(&cdb[1], 4, 5); /* SERVICE ACTION */ + switch (sa) { /* SERVICE ACTION */ + case SPC_MO_SET_TARGET_PORT_GROUPS: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MAINTENANCE_OUT: 0x%2.2x:SET_TARGET_PORT_GROUPS\n", conn->id, sa); + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d W_bit == 0\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + parameter_len = DGET32(&cdb[6]); + if (parameter_len == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, parameter_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (parameter_len < 4) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + /*ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "SET_TARGET_PORT_GROUPS", + lu_cmd->iobuf, parameter_len);*/ + getdata(data, lu_cmd) + /* data[0]-data[3] Reserved */ + /* Set target port group descriptor(s) */ + data_len = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, &data[4], parameter_len - 4); + if (data_len < 0) { + /* INVALID FIELD IN PARAMETER LIST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->data_len = parameter_len; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + default: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d MAINTENANCE_OUT: sa:0x%2.2x:unhandled\n", conn->id, sa); + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + break; + + case SPC_PERSISTENT_RESERVE_IN: + { + sa = BGET8W(&cdb[1], 4, 5); + if (lu_cmd->R_bit == 0) { + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_IN: sa:0x%2.2x R_bit == 0\n", conn->id, sa); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + allocation_len = DGET16(&cdb[7]); + data_alloc_len = allocation_len + 8192; + if (allocation_len > (size_t) max_alloc_size) { + ISTGT_ERRLOG("c#%d data_alloc_len(%d) too small\n", + conn->id, data_alloc_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + data = lu_cmd->data = xmalloc(data_alloc_len); + memset(data, 0, allocation_len); + MTX_LOCK(&spec->pr_rsv_mutex); + data_len = istgt_lu_disk_scsi_persistent_reserve_in(spec, conn, lu_cmd, sa, data, allocation_len); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (data_len < 0) { + /* status build by function */ + break; + } + if (data_len > data_alloc_len) { + ISTGT_ERRLOG("c#%d PRIN alen:%d dlen:%d/%d tlen:%d mem-issue", + conn->id, allocation_len, data_len, data_alloc_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "PERSISTENT_RESERVE_IN", data, data_len); + lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len); + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d PERSISTENT_RESERVE_IN sa:0x%2.2x data:%u/%u/%u\n", conn->id, sa, data_len, lu_cmd->transfer_len, allocation_len); + } + break; + + case SPC_PERSISTENT_RESERVE_OUT: + { + int scope, type; + sa = BGET8W(&cdb[1], 4, 5); + + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_OUT sa:0x%2.2x W_bit == 0\n", conn->id, sa); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + scope = BGET8W(&cdb[2], 7, 4); + type = BGET8W(&cdb[2], 3, 4); + parameter_len = DGET32(&cdb[5]); + + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, parameter_len); + if (rc < 0) { + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_OUT sa:0x%2.2x scope:%x type:%x plen:%d - disk_transfer_data failed:%d\n", + conn->id, sa, scope, type, parameter_len, rc); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (parameter_len < 24) { + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_OUT sa:0x%2.2x scope:%x type:%x plen:%d less than 24\n", + conn->id, sa, scope, type, parameter_len); + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + /*ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, + "PERSISTENT_RESERVE_OUT", + lu_cmd->iobuf, parameter_len);*/ + getdata(data, lu_cmd) + MTX_LOCK(&spec->pr_rsv_mutex); + data_len = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, lu_cmd, sa, scope, type, &data[0], parameter_len, 0); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (data_len < 0) { + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_OUT sa:0x%2.2x scope:%x type:%x plen:%d, function failed:%d\n", + conn->id, sa, scope, type, parameter_len, data_len); + /* status build by function */ + break; + } + lu_cmd->data_len = parameter_len; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + ISTGT_ERRLOG("c#%d PERSISTENT_RESERVE_OUT sa:0x%2.2x scope:%x type:%x plen:%d success (%d)", + conn->id, sa, scope, type, parameter_len, data_len); + } + break; + + /* XXX TODO: fix */ + case 0x85: /* ATA PASS-THROUGH(16) */ + case 0xA1: /* ATA PASS-THROUGH(12) */ + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + case SPC_EXTENDED_COPY: + { + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d EXTENDED_COPY\n", conn->id); + sa = BGET8W(&cdb[1], 4, 5); /* LID1 - 00h / LID4 - 01h */ + if (sa != 0x00) { + /* INVALID COMMAND SERVICE ACTION */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + rc = istgt_lu_disk_xcopy(spec, conn, lu_cmd); + if (rc < 0) { + /* build by function */ + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + case SPC2_RELEASE_6: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d RELEASE_6\n", conn->id); + if(spec->delay_release) + sleep(spec->delay_release); + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (rc < 0) { + /* build by function */ + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + case SPC2_RELEASE_10: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d RELEASE_10\n", conn->id); + if(spec->delay_release) + sleep(spec->delay_release); + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (rc < 0) { + /* build by function */ + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + case SPC2_RESERVE_6: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d RESERVE_6\n", conn->id); + if(spec->delay_reserve) + sleep(spec->delay_reserve); + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (rc < 0) { + /* build by function */ + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + case SPC2_RESERVE_10: + ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "c#%d RESERVE_10\n", conn->id); + if(spec->delay_reserve) + sleep(spec->delay_reserve); + MTX_LOCK(&spec->pr_rsv_mutex); + rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd); + MTX_UNLOCK(&spec->pr_rsv_mutex); + if (rc < 0) { + /* build by function */ + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + + case SBC_UNMAP: + if (spec->unmap) { + int pllen; + uint16_t unmap_datalen, block_des_datalen; + if(lu->limit_q_size != 0) + { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + break; + } + if (spec->rsv_key) { + rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0)); + if (rc != 0) { + ISTGT_ERRLOG("c#%d ISTGT_SCSI_STATUS_RESERVATION_CONFLICT\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + break; + } + } + pllen = DGET16(&cdb[7]); /* Parameter List Length */ + if (pllen == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, pllen); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (pllen < 4) { + /* INVALID FIELD IN CDB */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + getdata(data, lu_cmd) //data = lu_cmd->iobuf; + + unmap_datalen = DGET16(data); + block_des_datalen = DGET16(&data[2]); + if (block_des_datalen == 0) { + lu_cmd->data_len = 0; + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + if (pllen != unmap_datalen + 2) { + ISTGT_ERRLOG("c#%d unmap_datalen %d pllen %d not matching\n", conn->id, unmap_datalen, pllen); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + if (pllen != block_des_datalen + 8) { + ISTGT_ERRLOG("c#%d block_des_datalen %d pllen %d not matching\n", conn->id, block_des_datalen, pllen); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + rc = istgt_lu_disk_unmap(spec, conn, lu_cmd, data, pllen); + if (rc != 0) { + if(errno == EBUSY) + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + else + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + lu_cmd->status = ISTGT_SCSI_STATUS_GOOD; + break; + } + + default: + ISTGT_ERRLOG("c#%d LUN=0x%16.16"PRIx64" unsupported SCSI OP=0x%x\n", conn->id, lu_cmd->lun, cdb[0]); + /* INVALID COMMAND OPERATION CODE */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + break; + } + + if (lu_cmd->status == ISTGT_SCSI_STATUS_CHECK_CONDITION + || lu_cmd->status == ISTGT_SCSI_STATUS_GOOD) { + /* Do we need this? */ + MTX_LOCK(&spec->state_mutex); + if (lu_cmd->status == ISTGT_SCSI_STATUS_CHECK_CONDITION && spec->state == ISTGT_LUN_BUSY) { + msg = "(CheckCond_on_fake changed to Busy)"; dolog = 1; + lu_cmd->status = ISTGT_SCSI_STATUS_BUSY; + } + +#if 0 + else if(lu_cmd->status == ISTGT_SCSI_STATUS_GOOD && spec->state != ISTGT_LUN_BUSY) { + /* Read/Write the reservation from/to ZAP if previously failed */ + if(spec->persist){ + if (spec->rsv_pending & ISTGT_RSV_READ) //lock and check? + rereadrsv = 1; + } + else if (spec->rsv_pending & ISTGT_RSV_READ) + ISTGT_LOG("persist is off, but, read reservation is pending"); + } +#endif + MTX_UNLOCK(&spec->state_mutex); + } +#if 0 + if (rereadrsv == 1) { + /* Read/Write the reservation from/to ZAP if previously failed */ + MTX_LOCK(&spec->pr_rsv_mutex); + if (spec->rsv_pending & ISTGT_RSV_READ) { + rc = istgt_lu_disk_get_reservation(spec); + if (rc < 0) { + msg = "(istgt_lu_disk_get_reservation failed, will retry)"; dolog = 1; + } + } + MTX_UNLOCK(&spec->pr_rsv_mutex); + } +#endif + if (dolog == 1) { + ISTGT_LOG( + "c#%d LU%d.%lx: CSN:%x OP=0x%x/%x (%lu+%u) complete [%c:%ld.%9.9ld %c:%ld.%9.9ld]%s\n", + conn->id, lunum, lu_cmd->lun, lu_cmd->CmdSN, cdb[0], lu_cmd->status, lu_cmd->lba, lu_cmd->lblen, + lu_cmd->caller[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0], + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_sec, + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_nsec, + lu_cmd->caller[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0], + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_sec, + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_nsec, + msg); + } else { + ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, + "c#%d LU%d.%lx: CSN:%x OP=0x%x/%x (%lu+%u) complete [%c:%ld.%9.9ld %c:%ld.%9.9ld]%s\n", + conn->id, lunum, lu_cmd->lun, lu_cmd->CmdSN, cdb[0], lu_cmd->status, lu_cmd->lba, lu_cmd->lblen, + lu_cmd->caller[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0], + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_sec, + lu_cmd->tdiff[lu_cmd->_andx > 1 ? lu_cmd->_andx - 2 : 0].tv_nsec, + lu_cmd->caller[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0], + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_sec, + lu_cmd->tdiff[lu_cmd->_andx > 0 ? lu_cmd->_andx - 1 : 0].tv_nsec, + msg); + } + if ((data != NULL) && (freedata == 1)) + xfree(data); + return 0; +} diff --git a/src/istgt_lu_disk_vbox.c b/src/istgt_lu_disk_vbox.c new file mode 100644 index 00000000..f9a58bef --- /dev/null +++ b/src/istgt_lu_disk_vbox.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "istgt.h" +#include "istgt_log.h" +#include "istgt_misc.h" +#include "istgt_lu.h" +#include "istgt_proto.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#ifdef USE_VBOXVD +#define IN_RING3 +#include "iprt/buildconfig.h" +#include "VBox/vd.h" + +typedef struct istgt_lu_disk_vbox_t { + PVBOXHDD pDisk; + PVDINTERFACE pVDIfs; + PVDINTERFACE pVDIfsImage; + VDINTERFACE VDIfsDisk; + VDINTERFACEERROR VDIfError; + VDTYPE enmType; + RTUUID uuid; +} ISTGT_LU_DISK_VBOX; + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) +#endif + +static void istgt_lu_disk_vbox_error(void *pvUser, int rc, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list va) __attribute__((__format__(__printf__, 6, 0))); + +static void istgt_lu_disk_vbox_error(void *pvUser, int rc, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list va) +{ + ISTGT_LU_DISK *spec = (ISTGT_LU_DISK*)pvUser; + char buf[MAX_TMPBUF*2]; + + vsnprintf(buf, sizeof buf, pszFormat, va); + ISTGT_ERRLOG("LU%d: LUN%d: rc=%d, %s:%u:%s: %s", spec->num, spec->lun, + rc, pszFile, iLine, pszFunction, buf); +} + +static int +istgt_lu_disk_open_vbox(ISTGT_LU_DISK *spec, int flags, int mode __attribute__((__unused__))) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + PVDINTERFACE pIf; + uint32_t major, minor, build; + unsigned uOpenFlags; + int rc; + + major = RTBldCfgVersionMajor(); + minor = RTBldCfgVersionMinor(); + build = RTBldCfgVersionBuild(); + if (major > 4 || (major == 4 && minor >= 2)) { + // VBoxDDU >= 4.2 + if (ISTGT_VBOXINC_VERSION_MAJOR < 4 || + (ISTGT_VBOXINC_VERSION_MAJOR == 4 && ISTGT_VBOXINC_VERSION_MINOR < 2)) { + ISTGT_ERRLOG("VBox library is newer than istgt\n"); + return -1; + } + } else { + // VBoxDDU < 4.2 + if (ISTGT_VBOXINC_VERSION_MAJOR > 4 || + (ISTGT_VBOXINC_VERSION_MAJOR == 4 && ISTGT_VBOXINC_VERSION_MINOR >= 2)) { + ISTGT_ERRLOG("VBox library is older than istgt\n"); + return -1; + } + if (strcasecmp(spec->disktype, "QCOW") == 0 + || strcasecmp(spec->disktype, "QED") == 0 + || strcasecmp(spec->disktype, "VHDX") == 0) { + ISTGT_ERRLOG("VD format(%s) is not supported in this version.\n", + spec->disktype); + return -1; + } + } + + if ((flags & O_ACCMODE) == O_RDONLY) { + uOpenFlags = VD_OPEN_FLAGS_READONLY; + } else if ((flags & O_ACCMODE) == O_RDWR) { + uOpenFlags = VD_OPEN_FLAGS_NORMAL; + } else { + ISTGT_ERRLOG("not supported mode %x\n", (flags & O_ACCMODE)); + return -1; + } + + exspec->pDisk = NULL; + exspec->pVDIfs = NULL; + exspec->pVDIfsImage = NULL; + exspec->enmType = VDTYPE_HDD; + +#if ((ISTGT_VBOXINC_VERSION_MAJOR > 4) || (ISTGT_VBOXINC_VERSION_MAJOR == 4 && ISTGT_VBOXINC_VERSION_MINOR >= 2)) + exspec->VDIfError.pfnError = istgt_lu_disk_vbox_error; + exspec->VDIfError.pfnMessage = NULL; + pIf = (PVDINTERFACE)&exspec->VDIfError; + + rc = VDInterfaceAdd(pIf, "VD interface error", VDINTERFACETYPE_ERROR, + spec, sizeof(VDINTERFACEERROR), &exspec->pVDIfs); +#else /* VBox < 4.2 */ + exspec->VDIfError.cbSize = sizeof(VDINTERFACEERROR); + exspec->VDIfError.enmInterface = VDINTERFACETYPE_ERROR; + exspec->VDIfError.pfnError = istgt_lu_disk_vbox_error; + exspec->VDIfError.pfnMessage = NULL; + pIf = &exspec->VDIfsDisk; + + rc = VDInterfaceAdd(pIf, "VD interface error", VDINTERFACETYPE_ERROR, + &exspec->VDIfError, spec, &exspec->pVDIfs); +#endif /* VBox >= 4.2 */ + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDInterfaceAdd error\n"); + return -1; + } + + rc = VDCreate(exspec->pVDIfs, exspec->enmType, &exspec->pDisk); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDCreate error\n"); + VDInterfaceRemove(pIf, &exspec->pVDIfs); + exspec->pDisk = NULL; + exspec->pVDIfs = NULL; + exspec->pVDIfsImage = NULL; + return -1; + } + rc = VDOpen(exspec->pDisk, spec->disktype, spec->file, uOpenFlags, + exspec->pVDIfsImage); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDOpen error\n"); + VDDestroy(exspec->pDisk); + VDInterfaceRemove(pIf, &exspec->pVDIfs); + exspec->pDisk = NULL; + exspec->pVDIfs = NULL; + exspec->pVDIfsImage = NULL; + return -1; + } + return 0; +} + +static int +istgt_lu_disk_close_vbox(ISTGT_LU_DISK *spec) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + PVDINTERFACE pIf; + bool fDelete = false; + int rc; + +#if ((ISTGT_VBOXINC_VERSION_MAJOR > 4) || (ISTGT_VBOXINC_VERSION_MAJOR == 4 && ISTGT_VBOXINC_VERSION_MINOR >= 2)) + pIf = (PVDINTERFACE)&exspec->VDIfError; +#else /* VBox < 4.2 */ + pIf = &exspec->VDIfsDisk; +#endif /* VBox >= 4.2 */ + rc = VDClose(exspec->pDisk, fDelete); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDClose error\n"); + VDDestroy(exspec->pDisk); + VDInterfaceRemove(pIf, &exspec->pVDIfs); + exspec->pDisk = NULL; + exspec->pVDIfs = NULL; + exspec->pVDIfsImage = NULL; + return -1; + } + VDDestroy(exspec->pDisk); + VDInterfaceRemove(pIf, &exspec->pVDIfs); + exspec->pDisk = NULL; + exspec->pVDIfs = NULL; + exspec->pVDIfsImage = NULL; + return 0; +} + +static int64_t +istgt_lu_disk_seek_vbox(ISTGT_LU_DISK *spec, uint64_t offset) +{ + //ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + + spec->foffset = offset; + return 0; +} + +static int64_t +istgt_lu_disk_read_vbox(ISTGT_LU_DISK *spec, void *buf, uint64_t nbytes) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + uint64_t offset; + int rc; + + offset = spec->foffset; + rc = VDRead(exspec->pDisk, offset, buf, (size_t)nbytes); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDRead error\n"); + return -1; + } + spec->foffset += nbytes; + return (int64_t)nbytes; +} + +static int64_t +istgt_lu_disk_write_vbox(ISTGT_LU_DISK *spec, const void *buf, uint64_t nbytes) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + uint64_t offset; + int rc; + + offset = spec->foffset; + rc = VDWrite(exspec->pDisk, offset, buf, (size_t)nbytes); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDWrite error\n"); + return -1; + } + spec->foffset += nbytes; + return (int64_t)nbytes; +} + +static int64_t +istgt_lu_disk_sync_vbox(ISTGT_LU_DISK *spec, uint64_t offset __attribute__((__unused__)), uint64_t nbytes __attribute__((__unused__))) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + int rc; + + rc = VDFlush(exspec->pDisk); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("VDFlush error\n"); + return -1; + } + return 0; +} + +static int +istgt_lu_disk_allocate_vbox(ISTGT_LU_DISK *spec __attribute__((__unused__))) +{ + //ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + + return 0; +} + +static int +istgt_lu_disk_setcache_vbox(ISTGT_LU_DISK *spec) +{ + //ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + + if (spec->read_cache) { + } + if (spec->write_cache) { + } + return 0; +} + +int +istgt_lu_disk_vbox_lun_init(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu) +{ + ISTGT_LU_DISK_VBOX *exspec; + uint64_t capacity; + uint64_t fsize; + int flags; + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_vbox_lun_init\n"); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d for disktype=%s\n", + spec->num, spec->lun, spec->disktype); + + spec->open = istgt_lu_disk_open_vbox; + spec->close = istgt_lu_disk_close_vbox; + spec->seek = istgt_lu_disk_seek_vbox; + spec->read = istgt_lu_disk_read_vbox; + spec->write = istgt_lu_disk_write_vbox; + spec->sync = istgt_lu_disk_sync_vbox; + spec->allocate = istgt_lu_disk_allocate_vbox; + spec->setcache = istgt_lu_disk_setcache_vbox; + + exspec = xmalloc(sizeof *exspec); + memset(exspec, 0, sizeof *exspec); + spec->exspec = exspec; + + flags = lu->readonly ? O_RDONLY : O_RDWR; + rc = spec->open(spec, flags, 0666); + if (rc < 0) { + ISTGT_ERRLOG("LU%d: LUN%d: open error(rc=%d)\n", + spec->num, spec->lun, rc); + return -1; + } + + capacity = VDGetSize(exspec->pDisk, 0); + fsize = VDGetFileSize(exspec->pDisk, 0); + + spec->size = capacity; + spec->blocklen = 512; + spec->blockcnt = spec->size / spec->blocklen; + if (spec->blockcnt == 0) { + ISTGT_ERRLOG("LU%d: LUN%d: size zero\n", spec->num, spec->lun); + spec->close(spec); + return -1; + } + +#if 0 + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "LU%d: LUN%d file=%s, size=%"PRIu64"\n", + spec->num, spec->lun, spec->file, spec->size); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, + "LU%d: LUN%d %"PRIu64" blocks, %" + PRIu64" bytes/block\n", + spec->num, spec->lun, spec->blockcnt, spec->blocklen); +#endif + + printf("LU%d: LUN%d file=%s, size=%"PRIu64"\n", + spec->num, spec->lun, spec->file, spec->size); + printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n", + spec->num, spec->lun, spec->blockcnt, spec->blocklen); + + if (strcasecmp(spec->disktype, "VDI") == 0 + || strcasecmp(spec->disktype, "VHD") == 0 + || strcasecmp(spec->disktype, "VMDK") == 0) { + rc = VDGetUuid(exspec->pDisk, 0, &exspec->uuid); + if (RT_FAILURE(rc)) { + ISTGT_ERRLOG("LU%d: LUN%d: uuid error\n", spec->num, spec->lun); + spec->close(spec); + return -1; + } + printf("LU%d: LUN%d UUID=" + "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + spec->num, spec->lun, + exspec->uuid.Gen.u32TimeLow, + exspec->uuid.Gen.u16TimeMid, + exspec->uuid.Gen.u16TimeHiAndVersion, + exspec->uuid.Gen.u8ClockSeqHiAndReserved, + exspec->uuid.Gen.u8ClockSeqLow, + exspec->uuid.Gen.au8Node[0], + exspec->uuid.Gen.au8Node[1], + exspec->uuid.Gen.au8Node[2], + exspec->uuid.Gen.au8Node[3], + exspec->uuid.Gen.au8Node[4], + exspec->uuid.Gen.au8Node[5]); + } + return 0; +} + +int +istgt_lu_disk_vbox_lun_shutdown(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu __attribute__((__unused__))) +{ + ISTGT_LU_DISK_VBOX *exspec = (ISTGT_LU_DISK_VBOX *)spec->exspec; + int rc; + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_vbox_lun_shutdown\n"); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d for disktype=%s\n", + spec->num, spec->lun, spec->disktype); + + if (!spec->lu->readonly) { + rc = spec->sync(spec, 0, spec->size); + if (rc < 0) { + //ISTGT_ERRLOG("LU%d: lu_disk_sync() failed\n", lu->num); + /* ignore error */ + } + } + rc = spec->close(spec); + if (rc < 0) { + //ISTGT_ERRLOG("LU%d: lu_disk_close() failed\n", lu->num); + /* ignore error */ + } + + xfree(exspec); + spec->exspec = NULL; + return 0; +} +#else /* USE_VBOXVD */ +int +istgt_lu_disk_vbox_lun_init(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu __attribute__((__unused__))) +{ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d unsupported virtual disk\n", + spec->num, spec->lun); + return -1; +} + +int +istgt_lu_disk_vbox_lun_shutdown(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu __attribute__((__unused__))) +{ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d unsupported virtual disk\n", + spec->num, spec->lun); + return -1; +} +#endif /* USE_VBOXVD */ diff --git a/src/istgt_lu_disk_xcopy.c b/src/istgt_lu_disk_xcopy.c new file mode 100644 index 00000000..519b63fa --- /dev/null +++ b/src/istgt_lu_disk_xcopy.c @@ -0,0 +1,600 @@ +/* **************************************************************************** + * (C) Copyright 2014 CloudByte, Inc. + * All Rights Reserved. + * + * This program is an unpublished copyrighted work which is proprietary + * to CloudByte, Inc. and contains confidential information that is not + * to be reproduced or disclosed to any other person or entity without + * prior written consent from CloudByte, Inc. in each and every instance. + * + * WARNING: Unauthorized reproduction of this program as well as + * unauthorized preparation of derivative works based upon the + * program or distribution of copies by sale, rental, lease or + * lending are violations of federal copyright laws and state trade + * secret laws, punishable by civil and criminal penalties. + * + * + ****************************************************************************/ +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +#define getdata(data, lu_cmd) { \ + if (lu_cmd->iobufindx == -1) { \ + data = NULL; \ + ISTGT_ERRLOG("data null\n"); \ + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;\ + return -1; \ + } else { \ + /*?? malloc and copy over all data to data = lu_c*/\ + uint8_t *dptr; int _i; \ + for (_i = 0; _i <= lu_cmd->iobufindx; _i++) \ + _nb += lu_cmd->iobuf[_i].iov_len;\ + dptr = data = xmalloc(_nb);\ + for (_i = 0; _i <= lu_cmd->iobufindx; (dptr += lu_cmd->iobuf[_i].iov_len), _i++)\ + memcpy(dptr, lu_cmd->iobuf[_i].iov_base, lu_cmd->iobuf[_i].iov_len);\ + } \ +} + +#define PR_ALLOW(WE,EA,ALLRR,WERR,EARR) \ + ((((WE)&1) << 4) | (((EA)&1) << 3) | (((ALLRR)&1) << 2) \ + | (((WERR)&1) << 1) | (((EARR)&1) << 0)) + +#define BUILD_SENSE(SK,ASC,ASCQ) istgt_lu_scsi_build_sense_data(lu_cmd, ISTGT_SCSI_SENSE_ ## SK, (ASC), (ASCQ)) + +int +istgt_lu_disk_receive_copy_results(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + uint8_t *data = 0; + short int service_action; + int data_len = 0; + uint8_t *cdb = lu_cmd->cdb; + uint32_t allocation_len = DGET32(&cdb[10]); + + data_len = allocation_len; + if (data_len != 0) { + istgt_lu_disk_transfer_data(conn, lu_cmd, data_len); + } + + data = xmalloc(200); + service_action = BGET8W(&cdb[1], 4, 5); + + switch(service_action) { + case 0x00: /* Copy Status */ + { + /* ILLEGAL REQUEST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + return -1; + } + case 0x01: /* Receive data */ + { + /* ILLEGAL REQUEST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + return -1; + } + case 0x03: /* Operating parameters */ + { + DSET32(&data[0], 43); /* Available data (n-3) */ + BSET8W(&data[4], 0, SNLID); + DSET16(&data[8], MAX_CSCD_DESCRIPTOR_COUNT); + DSET16(&data[10], MAX_SEGMENT_DESCRIPTOR_COUNT); + DSET32(&data[12], MAX_DESCRIPTOR_LIST_LENGTH); + DSET32(&data[16], MAX_SEGMENT_LENGTH); + DSET32(&data[20], MAX_INLINE_DATA_LENGTH); + DSET32(&data[24], HELD_DATA_LIMIT); + DSET32(&data[28], MAX_STREAM_DEVICE_TRANSFER_SIZE); + DSET16(&data[34], TOTAL_CONCURRENT_COPIES); + DSET8(&data[36], MAX_CONCURRENT_COPIES); + DSET8(&data[37], DATA_SEGMENT_GRANULARITY); + DSET8(&data[38], INLINE_DATA_GRANULARITY); + DSET8(&data[39], HELD_DATA_GRANULARITY); + DSET8(&data[43], IMPLEMENTED_DESCRIPTOR_LIST_LENGTH); + DSET8(&data[44], SEGMENT_DESCRIPTOR_B2B); + DSET8(&data[45], SEGMENT_DESCRIPTOR_B2B_OFFSET); + DSET8(&data[46], CSCD_IDENTIFICATION_DESCRIPTOR); + break; + } + case 0x04: /* Failed segment details */ + { + /* ILLEGAL REQUEST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + return -1; + } + default: /* Illegal Request */ + { + /* ILLEGAL REQUEST */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00); + return -1; + } + } + + lu_cmd->data = data; + lu_cmd->data_len = allocation_len < 47 ? allocation_len : 47; + return 0; +} + +static uint64_t +istgt_lu_get_lid(uint64_t vid) +{ + uint64_t naa; + uint64_t enc; + + naa = 0x3; // Locally Assigned + + /* NAA + LOCALLY ADMINISTERED VALUE */ + enc = (naa & 0xfULL) << (64-4); // 4bits + enc |= vid & 0xfffffffffffffffULL; //60bits + + return enc; +} + +static ISTGT_LU_DISK * +istgt_find_xcopy_target(ISTGT_Ptr istgt, uint64_t identifier) +{ + ISTGT_LU_Ptr lu; + uint64_t LUI; + uint64_t id; + int i; + + if (istgt == NULL) + return NULL; + for (i = 0; i < MAX_LOGICAL_UNIT; i++) { + lu = istgt->logical_unit[i]; + if (lu == NULL) + continue; + /* Cloudbyte supports single lun for logical group so zero */ + LUI = istgt_get_lui(lu->name, 0 & 0xffffU); + id = istgt_lu_get_lid(LUI); + if (id == identifier) { + return (lu->lun[0].spec); + } + } + + return NULL; + +} + +static ISTGT_XCOPY_TGT * +istgt_get_xcopy_target(ISTGT_LU_DISK *spec, uint8_t *target_descriptor, ISTGT_LU_CMD_Ptr lu_cmd) +{ + ISTGT_XCOPY_TGT *target; + uint64_t identifier = 0; + uint16_t ripi; /* Relative Initiator Port identifier */ + //uint8_t *dvc_typ_param; + uint8_t identifier_length; + uint8_t td_opcode; + uint8_t pdt; /* Peripheral Device Type */ + int association; + int code_set; + int identifier_type; + int naa; + + + target = xmalloc(sizeof *target); + memset(target, 0, sizeof *target); + target->spec = NULL; + + td_opcode = DGET8(&target_descriptor[0]); + if (td_opcode != 0xE4 ) { + /* ILLEGAL REQUEST UNSUPPORTED TARGET DESCRIPTOR */ + ISTGT_ERRLOG("TARGET_DESCRIPTOR OPCODE NOT SUPPORTED %x \n", td_opcode); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x07); // Refer SCSI Primary Commands - 3 (SPC-3) + return NULL; + } + + pdt = BGET8W(&target_descriptor[1], 4, 5); + ripi = DGET16(&target_descriptor[2]); + + code_set = BGET8W(&target_descriptor[4], 3, 4); + if (code_set == 1) { + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Association and Identifier field contains Binary values \n"); + } + + association = BGET8W(&target_descriptor[5], 5, 2); + identifier_type = BGET8W(&target_descriptor[5], 3, 4); + identifier_length = DGET8(&target_descriptor[7]); + + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Association %d, Identifier_type %d, Identifier_length %d\n", association, identifier_type, identifier_length); + + if (identifier_type == NAA_IDENTIFIER) { + /* Naa based descriptor*/ + naa = BGET8W(&target_descriptor[8], 7, 4); + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Naa %d\n", naa); + if (naa == NAA_IDENTIFIER) { + /* Locally Assigned Descriptor */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,"Locally Assigned Descriptor\n"); + identifier = DGET64(&target_descriptor[8]); + } + } + else { + ISTGT_ERRLOG("Identifier Type not supported \n"); + return NULL; + } + + target->spec = istgt_find_xcopy_target(spec->lu->istgt, identifier); + if (target->spec == NULL) { + ISTGT_ERRLOG("Target not found \n"); + return NULL; + } + + if (! (pdt == PDT_DIRECT_ACCESS_BLK_DEV || pdt == PDT_SIMPLIFIED_DIRECT_ACCESS_DEV)) { + ISTGT_ERRLOG("INVALID peripheral device type %x\n", pdt); + return NULL; + } + + /* Relative initiator port zero specifies that any port can be used */ + if (ripi == 0) { + /* use any port */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Relative Initiator Port %d\n", ripi); + } + + target->pad = BGET8W(&target_descriptor[28], 2, 1); + target->block_len = DGET24(&target_descriptor[29]); + + return target; +} + +int +istgt_lu_disk_process_xcopy(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data_buf, int dlen) +{ + ISTGT_XCOPY_TGT *src_tgt = NULL, *dst_tgt= NULL; + uint64_t src_lba = 0, dst_lba = 0; /* Source and Destination logical block address */ + uint32_t num_of_blks_byts = 0; + uint8_t *src_td = NULL, *dst_td= NULL; /* Source Destination target descriptor*/ + uint8_t lstid = 0; /* List identifier */ + uint8_t sd_opcode = 0; /* segment Descriptor opcode support only 0x2h, 0xDh, 0xAh */ + uint8_t stdi, dtdi; /* Source target descriptor and Destination target descriptor index */ + off_t src_offset=0, dst_offset=0; + int rc = 0; /* result */ + int dc = 0, cat = 0; + int tdll = 0; /* Target and Segment Descriptor List Length */ + int len = 16; /* Actual block starts with the offset 16 */ + int str, list_id_usage, priority; /* sequential striped (str), No Receive Copy Results (NRCR), Priority */ + int num_tar_desc; /* Number of target descriptor */ + //uint32_t transfer_len = 0; /* Transfer length */ + int sdl = 0; /* Segment descriptor length */ + + if (spec == NULL) { /* This spec can be source target / destination target, should not be NULL*/ + ISTGT_ERRLOG("c#%d SPEC in the istgt_lu_disk_process_xcopy is NULL\n", conn->id); + goto fail; + } + + + /* List ID should be zero for XCOPY(LID1), if SNLID = 1 + * Refer section 6.4.3.2 of spc4r36s */ + lstid = DGET8(&data_buf[0]); + if (lstid != 0) { + /*ILLEGAL REQUEST INVALID FIELD IN PARAMETER LIST */ + ISTGT_ERRLOG("c#%d LST_ID is Non-Zero\n", conn->id); + //BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + //goto fail; + } + + priority = BGET8W(&data_buf[1], 2, 3); + if (priority == 0) { + /* High priority copy command */ + /* CloudByte: Currently does not support priority on the commands. */ + } + + str = BGET8W(&data_buf[1], 5, 1); + if (str == 1) { + /* sequential access */ + } + else { + /* May not be sequential */ + } + + list_id_usage = BGET8W(&data_buf[1], 4, 2); + if (list_id_usage == LIST_ID_USAGE) { + /* List_id_usage is 11b, which specifies that, + * the copy manager need not hold any data for tha application client, + * and the Extended copy commands list identifier value should only be zero + * Refer 6.4.3.2 of spc4r36s */ + ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "c#%d List_id_usage %d\n", conn->id, list_id_usage); + } else { + ISTGT_ERRLOG("c#%d List_id_usage is not valid \n", conn->id); + /*ILLEGAL REQUEST INVALID FIELD IN PARAMETER LIST */ + //BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00); + //goto fail; + } + + /* Number of target descriptors must not be more than MAXIMUM TARGET DESCRIPTOR COUNT */ + tdll = DGET16(&data_buf[2]); + num_tar_desc = tdll/CSCD_DESCRIPTOR_LENGTH; + if (num_tar_desc != MAX_CSCD_DESCRIPTOR_COUNT) { + /* ILLEGAL REQUEST: TOO MANY TARGET DESCRIPTORS */ + ISTGT_ERRLOG("c#%d TOO MANY TARGET DESCRIPTORS\n", conn->id); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x06); /* Refer spc4r36s */ + goto fail; + } + + DSET32(&data_buf[4], 0); /* Copy manager to ensure bytes 4 through 7 contains zero */ + + /* Fetch the segment descriptors to get the index for target descriptor */ + len = PARAMETER_HEADER_DATA + tdll; + + //need to come back to this one later.. if we need to have xcopy support + //while (((len + (PARAMETER_HEADER_DATA+tdll+(sdll))) <= dlen) && (len < (PARAMETER_HEADER_DATA+tdll+(sdll)))) + while (len +4 <= dlen) + { + sd_opcode = DGET8(&data_buf[len]); + if (!(sd_opcode == SEGMENT_DESCRIPTOR_B2B || sd_opcode == SEGMENT_DESCRIPTOR_B2B_OFFSET)) { + ISTGT_ERRLOG("c#%d SD OPCODE NOT SUPPORTED %x \n", conn->id, sd_opcode); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x09); // Refer SCSI Primary Commands - 3 (SPC-3) + goto fail; + } + + sdl = DGET16(&data_buf[len+2]); + + if (len+sdl > dlen) { + ISTGT_ERRLOG("c#%d SD data error we need to send COPY ABORTED %x \n", conn->id, sd_opcode); + BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x09); // Refer SCSI Primary Commands - 3 (SPC-3) + goto fail; + } + stdi = DGET16(&data_buf[len +4]); + dtdi = DGET16(&data_buf[len+6]); + + num_of_blks_byts = DGET16(&data_buf[len+10]); + src_lba = DGET64(&data_buf[len+12]); + dst_lba = DGET64(&data_buf[len+20]); + if (sd_opcode == 0xA){ + src_offset = DGET16(&data_buf[len+28]); + dst_offset = DGET16(&data_buf[len+30]); + } + + cat = BGET8W(&data_buf[len+1], 0, 1); + stdi = PARAMETER_HEADER_DATA + (stdi * CSCD_DESCRIPTOR_LENGTH); + dtdi = PARAMETER_HEADER_DATA + (dtdi * CSCD_DESCRIPTOR_LENGTH); + + src_td = &data_buf[stdi]; + dst_td = &data_buf[dtdi]; + + src_tgt = istgt_get_xcopy_target(spec, src_td, lu_cmd); + if (src_tgt == NULL) { + ISTGT_ERRLOG("c#%d Could not find the source target \n", conn->id); + goto fail; + } + + //if (src_td != dst_td) { + dst_tgt = istgt_get_xcopy_target(spec, dst_td, lu_cmd); + if (dst_tgt == NULL) { + ISTGT_ERRLOG("c#%d Could not find the destination target \n", conn->id); + goto fail; + } + //}else { + /* Source and Destination Targets are both same */ + //dst_tgt = src_tgt ; + //} + + if (sd_opcode != 0xA) { + src_offset = src_lba * src_tgt->block_len; + dst_offset = dst_lba *dst_tgt->block_len; + dc = BGET8W(&data_buf[len+1], 1, 1); + } + + src_tgt->lba = src_lba; + dst_tgt->lba = dst_lba; + src_tgt->offset = src_offset; + dst_tgt->offset = dst_offset; + + rc = istgt_lu_disk_lbxcopy(src_tgt, dst_tgt, conn, lu_cmd, dc, cat, num_of_blks_byts, sd_opcode); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_lbxcopy() failed\n", conn->id); + goto fail; + } + len += sdl+4; + xfree(src_tgt); + xfree(dst_tgt); + } + + return 0; + + fail: + if (src_tgt) + xfree(src_tgt); + if (dst_tgt) + xfree(dst_tgt); + return -1; +} + +int +istgt_lu_disk_xcopy(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd) +{ + uint32_t i = 0,pll = 0; + uint8_t *cdb; + uint8_t *data; + short int opcode = 0; + int rc = 0; + int _nb = 0; + + cdb = lu_cmd->cdb; /* Command Descriptor Block */ + + opcode = cdb[0]; + /* Check for the opcode */ + if (opcode != 0x83) { + ISTGT_ERRLOG("c#%d EXTENDED COPY command opcode seems to be wrong \n", conn->id); + return -1; + } + + pll = DGET32(&cdb[10]); + /* Check for the parameter list length */ + if (pll == 0) { + /* Prameter list length is zero Nothing to do */ + return 0; /* Success */ + } + + /* Parameter list length truncates the prarameter data */ + if (pll < 2) { + /* PARAMETER LIST LENGTH ERROR */ + BUILD_SENSE(ILLEGAL_REQUEST, 0x1A, 0x00); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + /* Check whether write bit is set, if not return with error condition */ + if (lu_cmd->W_bit == 0) { + ISTGT_ERRLOG("W_bit == 0\n"); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + /* Data-Out */ + rc = istgt_lu_disk_transfer_data(conn, lu_cmd, pll); + if (rc < 0) { + ISTGT_ERRLOG("c#%d lu_disk_transfer_data() failed\n", conn->id); + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + return -1; + } + + getdata(data, lu_cmd) + + /* Process the XCOPY data */ + rc = istgt_lu_disk_process_xcopy(spec, conn, lu_cmd, data, _nb); + if (rc < 0) { + ISTGT_ERRLOG("c#%d istgt_lu_disk_process_xcopy() failed\n", conn->id); + if (lu_cmd->status != ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) + lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION; + if (data != NULL) + xfree(data); + return rc; + } + + /* Reserved bytes should to be zeroed */ + DSET32(&cdb[1], 0); + DSET32(&cdb[5], 0); + DSET8(&cdb[9], 0); + DSET8(&cdb[14], 0); + for (i= 0; i<=pll; i++) { + DSET8(&data[i], 0); + } + + lu_cmd->data = data; + lu_cmd->data_len = pll; + return 0; +} + +static uint64_t +istgt_obtain_xcopy_nbytes(ISTGT_XCOPY_TGT *src_tgt, ISTGT_XCOPY_TGT *dst_tgt, int dc, uint64_t num_blks_byts, uint8_t sd_opcode) +{ + uint64_t nbytes = 0; + if (sd_opcode == 0x02) { + if (num_blks_byts == 0 && dc == 0) { + /* residual handle */ + } else if (num_blks_byts == 0 && dc == 1) { + /* residual handle */ + } else if (dc == 0) { + nbytes = num_blks_byts * src_tgt->block_len; + } else if (dc == 1) { + nbytes = num_blks_byts * dst_tgt->block_len; + } + }else { + nbytes = num_blks_byts; + } + return nbytes; +} + +int +istgt_lu_disk_lbxcopy(ISTGT_XCOPY_TGT *src_tgt, ISTGT_XCOPY_TGT *dst_tgt, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int dc, int cat, uint64_t num_blks_byts, uint8_t sd_opcode) +{ + uint64_t *clone_buf = NULL; + uint64_t maxlba; + uint64_t llen; + uint64_t nbytes; + int64_t rc; + + /* Check for the scsi reservation */ + if (src_tgt->spec->rsv_key) { + rc = istgt_lu_disk_check_pr(src_tgt->spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + return -1; + } + } + + /* Check for the scsi reservation */ + if (dst_tgt->spec->rsv_key) { + rc = istgt_lu_disk_check_pr(dst_tgt->spec, conn, PR_ALLOW(1,0,1,1,0)); + if (rc != 0) { + lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT; + return -1; + } + } + + nbytes = istgt_obtain_xcopy_nbytes(src_tgt, dst_tgt, dc, num_blks_byts, sd_opcode); + if (nbytes == 0) { + /* No data to copy */ + lu_cmd->data_len = 0; + return 0; + } + + maxlba = src_tgt->spec->blockcnt; + llen = (nbytes / src_tgt->block_len); + if (src_tgt->lba >= maxlba || llen > maxlba || src_tgt->lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media\n", conn->id); + return -1; + } + + + MTX_LOCK(&src_tgt->spec->clone_mutex); + clone_buf = xmalloc(nbytes); + rc = pread(src_tgt->spec->fd, clone_buf, nbytes, src_tgt->offset); + if (rc < 0 || (uint64_t) rc != nbytes) { + xfree(clone_buf); + /* CloudByte: TODO FIX, Refer spc4rs36 Table-118, Preserve the residual data + * for the next segment processing if the cat bit is being Non-zero */ + MTX_UNLOCK(&src_tgt->spec->clone_mutex); + if (src_tgt->pad == 0 && dst_tgt->pad == 0 && cat == 0) { + BUILD_SENSE(COPY_ABORTED, 0x26, 0x0A); /* Copy Aborted: Unexpected Inexact Segment */ + } + ISTGT_ERRLOG("c#%d lu_disk_read() failed, %d read: %ld\n", conn->id, errno, rc); + return -1; + } + + MTX_UNLOCK(&src_tgt->spec->clone_mutex); + + maxlba = dst_tgt->spec->blockcnt; + llen = (nbytes / dst_tgt->block_len); + if (dst_tgt->lba >= maxlba || llen > maxlba || dst_tgt->lba > (maxlba - llen)) { + ISTGT_ERRLOG("c#%d end of media\n", conn->id); + return -1; + } + + + if (dst_tgt->spec->lu->readonly) { + ISTGT_ERRLOG("c#%d LU%d: readonly unit\n", conn->id, dst_tgt->spec->lu->num); + return -1; + } + + MTX_LOCK(&dst_tgt->spec->clone_mutex); + rc = pwrite(dst_tgt->spec->fd, clone_buf, nbytes, dst_tgt->offset); + if (rc < 0 || (uint64_t) rc != nbytes) { + xfree(clone_buf); + /* CloudByte: TODO FIX, Refer sp4r36s Table-118, Preserve the residual data + * for the next segment processing if the cat bit being NON-Zero */ + MTX_UNLOCK(&dst_tgt->spec->clone_mutex); + if (src_tgt->pad == 0 && dst_tgt->pad == 0 && cat == 0) { + BUILD_SENSE(COPY_ABORTED, 0x26, 0x0A); /* Copy Aborted: Unexpected Inexact Segment */ + } + ISTGT_ERRLOG("c#%d lu_disk_write() failed, %d read: %ld\n", conn->id, errno, rc); + return -1; + } + xfree(clone_buf); + MTX_UNLOCK(&dst_tgt->spec->clone_mutex); + + return 0; +} + diff --git a/src/istgt_md5.c b/src/istgt_md5.c new file mode 100644 index 00000000..5a12abc2 --- /dev/null +++ b/src/istgt_md5.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +#include "istgt.h" +#include "istgt_md5.h" + +int +istgt_md5init(ISTGT_MD5CTX *md5ctx) +{ + int rc; + + if (md5ctx == NULL) + return -1; + rc = MD5_Init(&md5ctx->md5ctx); + return rc; +} + +int +istgt_md5final(void *md5, ISTGT_MD5CTX *md5ctx) +{ + int rc; + + if (md5ctx == NULL || md5 == NULL) + return -1; + rc = MD5_Final(md5, &md5ctx->md5ctx); + return rc; +} + +int +istgt_md5update(ISTGT_MD5CTX *md5ctx, const void *data, size_t len) +{ + int rc; + + if (md5ctx == NULL) + return -1; + if (data == NULL || len <= 0) + return 0; + rc = MD5_Update(&md5ctx->md5ctx, data, len); + return rc; +} diff --git a/src/istgt_md5.h b/src/istgt_md5.h new file mode 100644 index 00000000..42db4f9f --- /dev/null +++ b/src/istgt_md5.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_MD5_H +#define ISTGT_MD5_H + +#include + +#ifdef __FreeBSD__ +#include +#elif defined __linux__ +#include +#endif + +#define ISTGT_MD5DIGEST_LEN MD5_DIGEST_LENGTH + +typedef struct istgt_md5ctx_t { + MD5_CTX md5ctx; +} ISTGT_MD5CTX; + +int istgt_md5init(ISTGT_MD5CTX *md5ctx); +int istgt_md5final(void *md5, ISTGT_MD5CTX *md5ctx); +int istgt_md5update(ISTGT_MD5CTX *md5ctx, const void *data, size_t len); + +#endif /* ISTGT_MD5_H */ diff --git a/src/istgt_misc.c b/src/istgt_misc.c new file mode 100644 index 00000000..5ca12e6f --- /dev/null +++ b/src/istgt_misc.c @@ -0,0 +1,970 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_LIBPTHREAD +#include +#endif +#ifdef HAVE_SCHED +#include +#endif + +#include "istgt.h" +#include "istgt_misc.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2))); + +static void +fatal(const char *format, ...) +{ + char buf[MAX_TMPBUF]; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof buf, format, ap); + fprintf(stderr, "%s", buf); + syslog(LOG_ERR, "%s", buf); + va_end(ap); + exit(EXIT_FAILURE); +} + +typedef struct mem_hdr { + uint16_t pIdx; + uint16_t bIdx; + uint8_t inUse; + uint8_t dfree; + uint16_t line; + uint32_t alloccnt; + uint32_t freecnt; + char tinf[16]; +} mem_hdr_t; + +typedef struct memory_pool { + uint32_t objsize; + uint64_t frees; + uint64_t allocs; + uint32_t fail; + + uint32_t inuse; + uint32_t maxuse; + + void *startmem; + void *endmem; + + pthread_mutex_t mmtx; + uint16_t mapsize; //limits us to 64k objects per pool, should be looking at bits instead of uint8 + uint16_t bucksize; + uint8_t *usagemap; + uint64_t **bucket; + char name[12]; +} mpool_t; + +mpool_t mpools[50]; + +static int mpool_inited = 0; +static size_t mpool_minSize = 0; +static size_t mpool_maxSize = 0; + +//uint8_t PoolMap[MAX_SIZE+1]; +//uint32_t PoolSize[20] = { 4096, 8192, 12288, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +uint32_t PoolSizeActual[50] = {0} ; + +uint32_t poolBuckUsage[50] = { 0 }; +//uint32_t PoolSize[20] = { 1024, 2048, 3072, 4096, 5000, 6000, 8192, 12288, 16384, 32768, 65536, 131072, 262144, 307200, 524288, 0, 0, 0, 0, 0}; +//uint32_t poolBuckLimit[20] = { 1024, 1024, 1024, 1040, 800, 400, 600, 320, 120, 320, 120, 120, 120, 60, 120, 0, 0, 0, 0, 0}; +uint32_t PoolSize[50] = { 32, 64, 128, 256, 512, 1024, 2048, 3072, 4096, 5000, 6000, 8192, 12288, 16384, 32768, 65536, 131072, 262144, 307200, 524288, 590000, 856200, 1048680, 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}; +uint16_t poolBuckLimit[50] = { 700, 700, 400, 700, 4096, 4096, 2080, 1024, 1024, 500, 400, 600, 220, 220, 120, 220, 220, 220, 160, 50, 40, 100, 12, 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}; + +static int g_poolCnt = 0; +static uint64_t totalAlloc = 0; + +int detectDoubleFree = 0; + +static void *gstart = NULL; +static void *gend = NULL; +void +poolinit(void) +{ + int i = 0, j = 0, k = 0, rc; + uint64_t msize = 1000; + + FILE *fp = fopen("/etc/istgt-mem.conf", "r"); + if (fp) { + while(!feof(fp)) { + int psz = 0, plimit = 0; + int vals = fscanf(fp, "mem%d.%d\n", &psz, &plimit); + if (vals == 2) { + if (psz > 0 && psz < 1050000 && (uint32_t)psz > PoolSize[i-1]) { + PoolSize[i] = psz; + if (plimit < 0) + plimit = 0; + else if (plimit > 9000) + plimit = 9000; + poolBuckLimit[i] = plimit; + ++i; + } + } + if (i >= 50) + break; + } + fclose(fp); + fp = NULL; i = 0; + } + + for (i=0; i<50; ++i) { + if (PoolSize[i] != 0 && poolBuckLimit[i] != 0) + msize += ((PoolSize[i] + (sizeof (mem_hdr_t) * 3)) * poolBuckLimit[i]); + } + void *globalmem = malloc(msize); + uint8_t *gptr = globalmem; + + totalAlloc = msize; + gstart = gptr; + gend = gptr + (msize - 10); + + for (i=0, j=0; j<50; ++j) { + if ((PoolSize[j] != 0) && (poolBuckLimit[j] != 0)) { + snprintf(mpools[i].name, 11, "m:%x", PoolSize[j]); + mpools[i].objsize = PoolSize[j]; + mpools[i].frees = 0; + mpools[i].allocs = 0; + mpools[i].maxuse = 0; + mpools[i].inuse = 0; + mpools[i].fail = 0; + + mpools[i].bucksize = poolBuckLimit[j]; + mpools[i].mapsize = mpools[i].bucksize; + + mpools[i].bucket = malloc((sizeof (void *)) * (mpools[i].bucksize + 2)); + mpools[i].usagemap = malloc((sizeof (uint8_t)) * (mpools[i].mapsize + 2)); + memset(mpools[i].bucket, 0, (sizeof (void *)) * (mpools[i].bucksize + 2)); + memset(mpools[i].usagemap, 0, (sizeof (uint8_t)) * (mpools[i].mapsize + 2)); + + rc = pthread_mutex_init(&mpools[i].mmtx, NULL); + if (!mpools[i].bucket || !mpools[i].usagemap || rc != 0) { + ISTGT_ERRLOG("mempool init failed for %d)size:%d %x/%d [ %p %p %d ]\n", i, PoolSize[j], + mpools[i].bucksize, mpools[i].mapsize, mpools[i].bucket, mpools[i].usagemap, rc); + return; + } + mpools[i].startmem = gptr; + for (k=0; k ((uint8_t *)gend)) { + ISTGT_NOTICELOG("poolmem: %s %x %x overshot the intial alloc\n", mpools[i].name, mpools[i].bucksize, mpools[i].mapsize); + raise(11); + } + PoolSizeActual[i] = PoolSize[j]; + if (mpool_minSize == 0 || mpool_minSize > PoolSizeActual[i]) + mpool_minSize = PoolSizeActual[i] - 1; + if (mpool_maxSize < PoolSizeActual[i]) + mpool_maxSize = PoolSizeActual[i] + 1; + ++g_poolCnt; + ++i; + } + } + if (mpool_minSize < 256) //if we have a smaller pool, lets do all allocs from us + mpool_minSize = 0; + mpool_inited = 1; +} + + +void +poolfini(void) +{ + int i; + mpool_inited = 0; + for (i=0; i<50; ++i) { + PoolSizeActual[i] = 0; + if (mpools[i].bucket != NULL) + free(mpools[i].bucket); + if (mpools[i].usagemap != NULL) + free(mpools[i].usagemap); + + mpools[i].bucksize = 0; + mpools[i].mapsize = 0; + mpools[i].bucket = NULL; + mpools[i].usagemap = NULL; + mpools[i].maxuse = 0; + mpools[i].inuse = 0; + + pthread_mutex_destroy(&mpools[i].mmtx); + mpools[i].startmem = NULL; + mpools[i].endmem = NULL; + + } + //if (gstart != NULL) + // free(gstart); + gstart = NULL; + gend = NULL; +} + +static void +checkleak(int i) +{ + char buf[1024]; + int rem = 900; + char *ptr = buf; + int wn, k, e=0, jn=0; + uint32_t u=0, pr=0; + uint32_t osz = mpools[i].objsize; + for (k=0; kinUse == 0) { + ++e; //not expected + } else { + ++u; + wn = snprintf(ptr, rem, " %d.%.*s.%d.%d,", k, 14, mem->tinf, mem->line, mem->alloccnt); + if (wn < 0) + wn = 0; + else if (wn > rem) + wn = rem; + ptr += wn; rem -= wn; + if (rem < 40) { + ISTGT_NOTICELOG("L:%d [%u:%s]", osz, u-pr, buf); + ptr = buf; rem = 900; pr = u; + } + } + } else { + ++jn; + } + } + if (rem != 900) { + ISTGT_NOTICELOG("L:%d [%u:%s]", osz, u-pr, buf); + } +} + +int +poolprint(char *inbuf __attribute__((__unused__)), int len __attribute__((__unused__))) +{ + //char *ptr = inbuf; + //int wn, i; + //int rem = len - 3; + int i; + ISTGT_NOTICELOG("in: m:%9s %7s,%5s,%5s %5s allocs,frees", "poolsize", "total", "inuse", "max", "fail"); + for (i=0; i<50; ++i) { + if (mpools[i].bucksize == 0) + continue; + ISTGT_NOTICELOG("%2d: m:%9d %7d,%5d,%5d %5d %ld,%ld", + i, mpools[i].objsize, mpools[i].bucksize, mpools[i].inuse, mpools[i].maxuse, mpools[i].fail, mpools[i].allocs, mpools[i].frees); + /*wn = snprintf(ptr, rem, " m:%9d %7d,%5d,%5d %5d %ld,%ld", + mpools[i].objsize, mpools[i].bucksize, mpools[i].inuse, mpools[i].maxuse, mpools[i].fail, mpools[i].allocs, mpools[i].frees); + if (wn < 0) + wn = 0; + else if (wn > rem) + wn = rem; + ISTGT_NOTICELOG("%.*s", wn, ptr); + ptr += wn; rem -= wn; + if (rem < 40) { + ptr = inbuf; rem = len - 3; + }*/ + } + for (i=0; i<50; ++i) { + if (mpools[i].inuse > 0) + checkleak(i); + } + return 0; + //return (len - rem); +} + + + +int memdebug = 0; + +void * +xmalloci(size_t size, uint16_t line) +{ + void *p; + uint16_t i; + uint16_t pIdx = 0xffff; + uint16_t bIdx = 0xffff; + uint32_t inuse = -1; + uint16_t bucksize = -1; + uint32_t objsz = 0; + + if (size < 1) + size = 1; + + if (mpool_inited == 1 && + (size > mpool_minSize && size < mpool_maxSize)) { + for (i=0; i= size) { + pIdx = i; + break; + } + } + if (pIdx != 0xffff) { + uint16_t umsz = mpools[pIdx].mapsize; + uint8_t *umap = mpools[pIdx].usagemap; + + pthread_mutex_lock(&mpools[pIdx].mmtx); + objsz = mpools[pIdx].objsize; + inuse = mpools[pIdx].inuse; + bucksize = mpools[pIdx].bucksize; + if (mpools[pIdx].inuse < mpools[pIdx].bucksize) { + for (i=0; i < umsz; ++i) { + if (umap[i] == 0) { + umap[i] = 1; + bIdx = i; + ++mpools[pIdx].allocs; + ++mpools[pIdx].inuse; + if (mpools[pIdx].inuse > mpools[pIdx].maxuse) + mpools[pIdx].maxuse = mpools[pIdx].inuse; + break; + } + } + } + if (bIdx == 0xffff) { + ++mpools[pIdx].fail; + if (mpools[pIdx].inuse < mpools[pIdx].bucksize) { + raise(11); + } + } + pthread_mutex_unlock(&mpools[pIdx].mmtx); + if (bIdx != 0xffff) { + uint64_t *m = mpools[pIdx].bucket[bIdx]; + p = (void *)(((uint8_t *)m) + sizeof(mem_hdr_t)); + + mem_hdr_t *mem = (mem_hdr_t *)m; + mem->pIdx = pIdx; mem->bIdx = bIdx; + if ((mem->inUse == 1) || (mem->freecnt != mem->alloccnt)) { + ISTGT_NOTICELOG("poolalloc:issue %p inuse:%d.%d c:%u/%u ln:%d.%s:%d) [%d/%d]", + p, mem->inUse, mem->dfree, mem->alloccnt, mem->freecnt, + mem->line, mem->tinf, line, mem->pIdx, mem->bIdx); + if (detectDoubleFree == 1) + raise(11); + } + ++mem->alloccnt; + mem->inUse = 1; + memcpy(mem->tinf, tinfo, 16); + mem->line = line; + if (memdebug == 1) { + mem_hdr_t *mx = (mem_hdr_t *)(((uint8_t *)p) - sizeof (mem_hdr_t)); + ISTGT_NOTICELOG("poolalloc: %s size:%ld Idx:%d/%d %d/%d %p/%p %p", + tinfo, size, pIdx, mx->pIdx, bIdx, mx->bIdx, + m, mx, p); + } + return p; + } + } + } + + p = malloc(size); + if (p == NULL) + fatal("no memory\n"); + + ISTGT_TRACELOG(ISTGT_TRACE_MEM, "alloc:%p:size:%lu %s:%d [pool:%u %d/%d]", p, size, tinfo, line, objsz, inuse, bucksize); + return p; +} + +void +xfreei(void *p, uint16_t line) +{ + if (p == NULL) + return; + + //simple way to check if its our pools + if (p >= gstart && p < gend) { + mem_hdr_t *m = (mem_hdr_t *)(((uint8_t *)p) - sizeof (mem_hdr_t)); + pthread_mutex_lock(&mpools[m->pIdx].mmtx); + if ((m->inUse == 0) || ((m->freecnt+1) != m->alloccnt)) { + uint16_t pi = m->pIdx, bi = m->bIdx, ln = m->line; + uint8_t df = ++m->dfree; + if (detectDoubleFree == 1) { + ISTGT_NOTICELOG("poolfree:issue %s %p (%p) Idx:%d/%d (freed:%d/%d, %d)", tinfo, p, m, pi, bi, ln, line, df); + raise(11); + } else { + pthread_mutex_unlock(&mpools[m->pIdx].mmtx); + ISTGT_NOTICELOG("poolfree:issue %s %p (%p) Idx:%d/%d (freed:%d/%d, %d)", tinfo, p, m, pi, bi, ln, line, df); + return; + } + } + mpools[m->pIdx].usagemap[m->bIdx] = 0; + ++mpools[m->pIdx].frees; + --mpools[m->pIdx].inuse; + ++m->freecnt; + m->inUse = 0; + m->line = line; + pthread_mutex_unlock(&mpools[m->pIdx].mmtx); + if (memdebug == 1) { + ISTGT_NOTICELOG("poolfree: %s %p (%p) Idx:%d/%d", tinfo, p, m, m->pIdx, m->bIdx); + } + return; + } + + ISTGT_TRACELOG(ISTGT_TRACE_MEM, " free:%p: %s:%d", p, tinfo, line); + free(p); +} + +char * +xstrdupi(const char *s, uint16_t line) +{ + char *p; + size_t size; + + if (s == NULL) + return NULL; + size = strlen(s) + 1; + p = xmalloci(size, line); + memcpy(p, s, size - 1); + p[size - 1] = '\0'; + return p; +} + +char * +strlwr(char *s) +{ + char *p; + + if (s == NULL) + return NULL; + + p = s; + while (*p != '\0') { + *p = tolower((int) *p); + p++; + } + return s; +} + +char * +strupr(char *s) +{ + char *p; + + if (s == NULL) + return NULL; + + p = s; + while (*p != '\0') { + *p = toupper((int) *p); + p++; + } + return s; +} + +char * +strsepq(char **stringp, const char *delim) +{ + char *p, *q, *r; + int quoted = 0, bslash = 0; + + p = *stringp; + if (p == NULL) + return NULL; + + r = q = p; + while (*q != '\0' && *q != '\n') { + /* eat quoted characters */ + if (bslash) { + bslash = 0; + *r++ = *q++; + continue; + } else if (quoted) { + if (quoted == '"' && *q == '\\') { + bslash = 1; + q++; + continue; + } else if (*q == quoted) { + quoted = 0; + q++; + continue; + } + *r++ = *q++; + continue; + } else if (*q == '\\') { + bslash = 1; + q++; + continue; + } else if (*q == '"' || *q == '\'') { + quoted = *q; + q++; + continue; + } + + /* separator? */ + if (strchr(delim, (int) *q) == NULL) { + *r++ = *q++; + continue; + } + + /* new string */ + q++; + break; + } + *r = '\0'; + + /* skip tailer */ + while (*q != '\0' && strchr(delim, (int) *q) != NULL) { + q++; + } + if (*q != '\0') { + *stringp = q; + } else { + *stringp = NULL; + } + + return p; +} + +char * +trim_string(char *s) +{ + char *p, *q; + + if (s == NULL) + return NULL; + + /* remove header */ + p = s; + while (*p != '\0' && isspace((int) *p)) { + p++; + } + /* remove tailer */ + q = p + strlen(p); + while (q - 1 >= p && isspace((int) *(q - 1))) { + q--; + *q = '\0'; + } + /* if remove header, move */ + if (p != s) { + q = s; + while (*p != '\0') { + *q++ = *p++; + } + } + return s; +} + +char * +escape_string(const char *s) +{ + const char *p; + char *q, *r; + size_t size; + + if (s == NULL) + return NULL; + + p = s; + size = 0; + while (*p != '\0') { + if (*p == '"' || *p == '\\' || *p == '\'') { + size += 2; + } else { + size++; + } + p++; + } + + p = s; + r = q = xmalloc(size + 1); + while (*p != '\0') { + if (*p == '"' || *p == '\\' || *p == '\'') { + *q++ = '\\'; + *q++ = *p++; + } else { + *q++ = *p++; + } + } + *q++ = '\0'; + return r; +} + +/* LBA = (M * 60 + S) * 75 + F - 150 */ +uint32_t +istgt_msf2lba(uint32_t msf) +{ + uint32_t lba; + + lba = ((msf >> 16) & 0xff) * 60 * 75; + lba += ((msf >> 8) & 0xff) * 75; + lba += msf & 0xff; + lba -= 150; + return lba; +} + +uint32_t +istgt_lba2msf(uint32_t lba) +{ + uint32_t m, s, f; + + lba += 150; + m = (lba / 75) / 60; + s = (lba / 75) % 60; + f = lba % 75; + + return ((m << 16) | (s << 8) | f); +} + +uint8_t +istgt_dget8(const uint8_t *data) +{ + uint8_t value; + + value = (data[0] & 0xffU) << 0; + return value; +} + +void +istgt_dset8(uint8_t *data, uint32_t value) +{ + data[0] = (value >> 0) & 0xffU; +} + +uint16_t +istgt_dget16(const uint8_t *data) +{ + uint16_t value; + + value = (data[0] & 0xffU) << 8; + value |= (data[1] & 0xffU) << 0; + return value; +} + +void +istgt_dset16(uint8_t *data, uint32_t value) +{ + data[0] = (value >> 8) & 0xffU; + data[1] = (value >> 0) & 0xffU; +} + +uint32_t +istgt_dget24(const uint8_t *data) +{ + uint32_t value; + + value = (data[0] & 0xffU) << 16; + value |= (data[1] & 0xffU) << 8; + value |= (data[2] & 0xffU) << 0; + return value; +} + +void +istgt_dset24(uint8_t *data, uint32_t value) +{ + data[0] = (value >> 16) & 0xffU; + data[1] = (value >> 8) & 0xffU; + data[2] = (value >> 0) & 0xffU; +} + +uint32_t +istgt_dget32(const uint8_t *data) +{ + uint32_t value; + + value = (data[0] & 0xffU) << 24; + value |= (data[1] & 0xffU) << 16; + value |= (data[2] & 0xffU) << 8; + value |= (data[3] & 0xffU) << 0; + return value; +} + +void +istgt_dset32(uint8_t *data, uint32_t value) +{ + data[0] = (value >> 24) & 0xffU; + data[1] = (value >> 16) & 0xffU; + data[2] = (value >> 8) & 0xffU; + data[3] = (value >> 0) & 0xffU; +} + +uint64_t +istgt_dget48(const uint8_t *data) +{ + uint64_t value; + + value = (data[0] & 0xffULL) << 40; + value |= (data[1] & 0xffULL) << 32; + value |= (data[2] & 0xffULL) << 24; + value |= (data[3] & 0xffULL) << 16; + value |= (data[4] & 0xffULL) << 8; + value |= (data[5] & 0xffULL) << 0; + return value; +} + +void +istgt_dset48(uint8_t *data, uint64_t value) +{ + data[0] = (value >> 40) & 0xffULL; + data[1] = (value >> 32) & 0xffULL; + data[2] = (value >> 24) & 0xffULL; + data[3] = (value >> 16) & 0xffULL; + data[4] = (value >> 8) & 0xffULL; + data[5] = (value >> 0) & 0xffULL; +} + +uint64_t +istgt_dget64(const uint8_t *data) +{ + uint64_t value; + + value = (data[0] & 0xffULL) << 56; + value |= (data[1] & 0xffULL) << 48; + value |= (data[2] & 0xffULL) << 40; + value |= (data[3] & 0xffULL) << 32; + value |= (data[4] & 0xffULL) << 24; + value |= (data[5] & 0xffULL) << 16; + value |= (data[6] & 0xffULL) << 8; + value |= (data[7] & 0xffULL) << 0; + return value; +} + +void +istgt_dset64(uint8_t *data, uint64_t value) +{ + data[0] = (value >> 56) & 0xffULL; + data[1] = (value >> 48) & 0xffULL; + data[2] = (value >> 40) & 0xffULL; + data[3] = (value >> 32) & 0xffULL; + data[4] = (value >> 24) & 0xffULL; + data[5] = (value >> 16) & 0xffULL; + data[6] = (value >> 8) & 0xffULL; + data[7] = (value >> 0) & 0xffULL; +} + +void +istgt_dump(const char *label, const uint8_t *buf, size_t len) +{ + istgt_fdump(stdout, label, buf, len); +} + +void +istgt_fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len) +{ + char tmpbuf[MAX_TMPBUF]; + char buf8[8+1] = { 0 }; + size_t total; + size_t idx; + + fprintf(fp, "%s\n", label); + + total = 0; + for (idx = 0; idx < len; idx++) { + if (idx != 0 && idx % 8 == 0) { + total += snprintf(tmpbuf + total, sizeof tmpbuf - total, + "%s", buf8); + fprintf(fp, "%s\n", tmpbuf); + total = 0; + } + total += snprintf(tmpbuf + total, sizeof tmpbuf - total, + "%2.2x ", buf[idx] & 0xff); + buf8[idx % 8] = isprint(buf[idx]) ? buf[idx] : '.'; + } + for ( ; idx % 8 != 0; idx++) { + total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " "); + buf8[idx % 8] = ' '; + } + total += snprintf(tmpbuf + total, sizeof tmpbuf - total, "%s", buf8); + fprintf(fp, "%s\n", tmpbuf); + fflush(fp); +} + +#ifndef HAVE_SRANDOMDEV +#include +void +srandomdev(void) +{ + unsigned long seed; + time_t now; + pid_t pid; + + pid = getpid(); + now = time(NULL); + seed = pid ^ now; + srandom(seed); +} +#endif /* HAVE_SRANDOMDEV */ + +#ifndef HAVE_ARC4RANDOM +static int istgt_arc4random_initialized = 0; + +uint32_t +arc4random(void) +{ + uint32_t r; + uint32_t r1, r2; + + if (!istgt_arc4random_initialized) { + srandomdev(); + istgt_arc4random_initialized = 1; + } + r1 = (uint32_t) (random() & 0xffff); + r2 = (uint32_t) (random() & 0xffff); + r = (r1 << 16) | r2; + return r; +} +#endif /* HAVE_ARC4RANDOM */ + +void +istgt_gen_random(uint8_t *buf, size_t len) +{ +#ifdef USE_RANDOM + long l; + size_t idx; + + srandomdev(); + for (idx = 0; idx < len; idx++) { + l = random(); + buf[idx] = (uint8_t) l; + } +#else + uint32_t r; + size_t idx; + + for (idx = 0; idx < len; idx++) { + r = arc4random(); + buf[idx] = (uint8_t) r; + } +#endif /* USE_RANDOM */ +} + +int +istgt_bin2hex(char *buf, size_t len, const uint8_t *data, size_t data_len) +{ + const char *digits = "0123456789ABCDEF"; + size_t total = 0; + size_t idx; + + if (len < 3) + return -1; + buf[total] = '0'; + total++; + buf[total] = 'x'; + total++; + buf[total] = '\0'; + + for (idx = 0; idx < data_len; idx++) { + if (total + 3 > len) { + buf[total] = '\0'; + return - 1; + } + buf[total] = digits[(data[idx] >> 4) & 0x0fU]; + total++; + buf[total] = digits[data[idx] & 0x0fU]; + total++; + } + buf[total] = '\0'; + return total; +} + +int +istgt_hex2bin(uint8_t *data, size_t data_len, const char *str) +{ + const char *digits = "0123456789ABCDEF"; + const char *dp; + const char *p; + size_t total = 0; + int n0, n1; + + p = str; + if (p[0] != '0' && (p[1] != 'x' && p[1] != 'X')) + return -1; + p += 2; + + while (p[0] != '\0' && p[1] != '\0') { + if (total >= data_len) { + return -1; + } + dp = strchr(digits, toupper((int) p[0])); + if (dp == NULL) { + return -1; + } + n0 = (int) (dp - digits); + dp = strchr(digits, toupper((int) p[1])); + if (dp == NULL) { + return -1; + } + n1 = (int) (dp - digits); + + data[total] = (uint8_t) (((n0 & 0x0fU) << 4) | (n1 & 0x0fU)); + total++; + p += 2; + } + return total; +} + +void +istgt_yield(void) +{ +#if defined (HAVE_PTHREAD_YIELD) + pthread_yield(); +#elif defined (HAVE_SCHED_YIELD) + sched_yield(); +#else + usleep(0); +#endif +} + +#ifndef HAVE_STRLCPY +size_t +strlcpy(char *dst, const char *src, size_t size) +{ + size_t len; + + if (dst == NULL) + return 0; + if (size < 1) { + return 0; + } + len = strlen(src); + if (len > size - 1) { + len = size - 1; + } + memcpy(dst, src, len); + dst[len] = '\0'; + return len; +} +#endif /* HAVE_STRLCPY */ diff --git a/src/istgt_misc.h b/src/istgt_misc.h new file mode 100644 index 00000000..aa09d874 --- /dev/null +++ b/src/istgt_misc.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2008-2010 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_MISC_H +#define ISTGT_MISC_H + +#include +#include +#include + +#define ISTGT_USE_MACRO_EXPAND + +#ifdef ISTGT_USE_MACRO_EXPAND +#define DSET8(B,D) (*((uint8_t *)(B)) = (uint8_t)(D)) +#define DSET16(B,D) \ + (((*((uint8_t *)(B)+0)) = (uint8_t)((uint16_t)(D) >> 8)), \ + ((*((uint8_t *)(B)+1)) = (uint8_t)((uint16_t)(D) >> 0))) +#define DSET24(B,D) \ + (((*((uint8_t *)(B)+0)) = (uint8_t)((uint32_t)(D) >> 16)), \ + ((*((uint8_t *)(B)+1)) = (uint8_t)((uint32_t)(D) >> 8)), \ + ((*((uint8_t *)(B)+2)) = (uint8_t)((uint32_t)(D) >> 0))) +#define DSET32(B,D) \ + (((*((uint8_t *)(B)+0)) = (uint8_t)((uint32_t)(D) >> 24)), \ + ((*((uint8_t *)(B)+1)) = (uint8_t)((uint32_t)(D) >> 16)), \ + ((*((uint8_t *)(B)+2)) = (uint8_t)((uint32_t)(D) >> 8)), \ + ((*((uint8_t *)(B)+3)) = (uint8_t)((uint32_t)(D) >> 0))) +#define DSET48(B,D) \ + (((*((uint8_t *)(B)+0)) = (uint8_t)((uint64_t)(D) >> 40)), \ + ((*((uint8_t *)(B)+1)) = (uint8_t)((uint64_t)(D) >> 32)), \ + ((*((uint8_t *)(B)+2)) = (uint8_t)((uint64_t)(D) >> 24)), \ + ((*((uint8_t *)(B)+3)) = (uint8_t)((uint64_t)(D) >> 16)), \ + ((*((uint8_t *)(B)+4)) = (uint8_t)((uint64_t)(D) >> 8)), \ + ((*((uint8_t *)(B)+5)) = (uint8_t)((uint64_t)(D) >> 0))) +#define DSET64(B,D) \ + (((*((uint8_t *)(B)+0)) = (uint8_t)((uint64_t)(D) >> 56)), \ + ((*((uint8_t *)(B)+1)) = (uint8_t)((uint64_t)(D) >> 48)), \ + ((*((uint8_t *)(B)+2)) = (uint8_t)((uint64_t)(D) >> 40)), \ + ((*((uint8_t *)(B)+3)) = (uint8_t)((uint64_t)(D) >> 32)), \ + ((*((uint8_t *)(B)+4)) = (uint8_t)((uint64_t)(D) >> 24)), \ + ((*((uint8_t *)(B)+5)) = (uint8_t)((uint64_t)(D) >> 16)), \ + ((*((uint8_t *)(B)+6)) = (uint8_t)((uint64_t)(D) >> 8)), \ + ((*((uint8_t *)(B)+7)) = (uint8_t)((uint64_t)(D) >> 0))) +#define DGET8(B) (*((uint8_t *)(B))) +#define DGET16(B) \ + ((( (uint16_t) *((uint8_t *)(B)+0)) << 8) \ + | (((uint16_t) *((uint8_t *)(B)+1)) << 0)) +#define DGET24(B) \ + ((( (uint32_t) *((uint8_t *)(B)+0)) << 16) \ + | (((uint32_t) *((uint8_t *)(B)+1)) << 8) \ + | (((uint32_t) *((uint8_t *)(B)+2)) << 0)) +#define DGET32(B) \ + ((( (uint32_t) *((uint8_t *)(B)+0)) << 24) \ + | (((uint32_t) *((uint8_t *)(B)+1)) << 16) \ + | (((uint32_t) *((uint8_t *)(B)+2)) << 8) \ + | (((uint32_t) *((uint8_t *)(B)+3)) << 0)) +#define DGET48(B) \ + ((( (uint64_t) *((uint8_t *)(B)+0)) << 40) \ + | (((uint64_t) *((uint8_t *)(B)+1)) << 32) \ + | (((uint64_t) *((uint8_t *)(B)+2)) << 24) \ + | (((uint64_t) *((uint8_t *)(B)+3)) << 16) \ + | (((uint64_t) *((uint8_t *)(B)+4)) << 8) \ + | (((uint64_t) *((uint8_t *)(B)+5)) << 0)) +#define DGET64(B) \ + ((( (uint64_t) *((uint8_t *)(B)+0)) << 56) \ + | (((uint64_t) *((uint8_t *)(B)+1)) << 48) \ + | (((uint64_t) *((uint8_t *)(B)+2)) << 40) \ + | (((uint64_t) *((uint8_t *)(B)+3)) << 32) \ + | (((uint64_t) *((uint8_t *)(B)+4)) << 24) \ + | (((uint64_t) *((uint8_t *)(B)+5)) << 16) \ + | (((uint64_t) *((uint8_t *)(B)+6)) << 8) \ + | (((uint64_t) *((uint8_t *)(B)+7)) << 0)) +#else /* ISTGT_USE_MACRO_EXPAND */ +//#define DSET8(B,D) (istgt_dset8((B),(D))) +#define DSET8(B,D) (*((uint8_t *)(B)) = (uint8_t)(D)) +#define DSET16(B,D) (istgt_dset16((B),(D))) +#define DSET24(B,D) (istgt_dset24((B),(D))) +#define DSET32(B,D) (istgt_dset32((B),(D))) +#define DSET48(B,D) (istgt_dset48((B),(D))) +#define DSET64(B,D) (istgt_dset64((B),(D))) +//#define DGET8(B) (istgt_dget8((B))) +#define DGET8(B) (*((uint8_t *)(B))) +#define DGET16(B) (istgt_dget16((B))) +#define DGET24(B) (istgt_dget24((B))) +#define DGET32(B) (istgt_dget32((B))) +#define DGET48(B) (istgt_dget48((B))) +#define DGET64(B) (istgt_dget64((B))) +#endif /* ISTGT_USE_MACRO_EXPAND */ + +#define DMIN8(A,B) ((uint8_t) ((A) > (B) ? (B) : (A))) +#define DMIN16(A,B) ((uint16_t) ((A) > (B) ? (B) : (A))) +#define DMIN24(A,B) ((uint32_t) ((A) > (B) ? (B) : (A))) +#define DMIN32(A,B) ((uint32_t) ((A) > (B) ? (B) : (A))) +#define DMIN48(A,B) ((uint64_t) ((A) > (B) ? (B) : (A))) +#define DMIN64(A,B) ((uint64_t) ((A) > (B) ? (B) : (A))) +#define DMAX8(A,B) ((uint8_t) ((A) > (B) ? (A) : (B))) +#define DMAX16(A,B) ((uint16_t) ((A) > (B) ? (A) : (B))) +#define DMAX24(A,B) ((uint32_t) ((A) > (B) ? (A) : (B))) +#define DMAX32(A,B) ((uint32_t) ((A) > (B) ? (A) : (B))) +#define DMAX48(A,B) ((uint64_t) ((A) > (B) ? (A) : (B))) +#define DMAX64(A,B) ((uint64_t) ((A) > (B) ? (A) : (B))) + +#define BSHIFTNW(N,W) (((W) > 0) ? (((N) > ((W)-1)) ? ((N) - ((W)-1)) : 0) : 0) +#define BMASKW(W) (((W) > 0) ? (~((~0U) << (W))) : 0) + +#define BDSET8W(B,D,N,W) DSET8((B),(((D)&BMASKW((W)))<> BSHIFTNW((N),(W))) & BMASKW((W))) + +#define BDSET8(B,D,N) (BDSET8W((B),(D),(N),1)) +#define BDADD8(B,D,N) (BDADD8W((B),(D),(N),1)) +#define BSET8(B,N) (BSET8W((B),(N),1)) +#define BCLR8(B,N) (BCLR8W((B),(N),1)) +#define BGET8(B,N) (BGET8W((B),(N),1)) + +#define BGET32(B,N) (((B) >> (N)) & 1) +#define BSET32(B,N) ((B) |= ((uint32_t)((1) << (N)))) +#define BUNSET32(B,N) ((B) &= ((uint32_t)(~((uint32_t)((1) << (N)))))) + +/* memory allocate */ +#define xmalloc(size) xmalloci((size), __LINE__) +#define xfree(p) xfreei((p), __LINE__) +#define xstrdup(s) xstrdupi((s), __LINE__) +void *xmalloci(size_t size, uint16_t line); +void xfreei(void *p, uint16_t line); +char *xstrdupi(const char *s, uint16_t line); + +/* string functions */ +char *strlwr(char *s); +char *strupr(char *s); +char *strsepq(char **stringp, const char *delim); +char *trim_string(char *s); +char *escape_string(const char *s); +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size); +#endif /* HAVE_STRLCPY */ + +/* convert from/to LBA/MSF */ +uint32_t istgt_msf2lba(uint32_t msf); +uint32_t istgt_lba2msf(uint32_t lba); + +/* network byte order operation */ +uint8_t istgt_dget8(const uint8_t *data); +void istgt_dset8(uint8_t *data, uint32_t value); +uint16_t istgt_dget16(const uint8_t *data); +void istgt_dset16(uint8_t *data, uint32_t value); +uint32_t istgt_dget24(const uint8_t *data); +void istgt_dset24(uint8_t *data, uint32_t value); +uint32_t istgt_dget32(const uint8_t *data); +void istgt_dset32(uint8_t *data, uint32_t value); +uint64_t istgt_dget48(const uint8_t *data); +void istgt_dset48(uint8_t *data, uint64_t value); +uint64_t istgt_dget64(const uint8_t *data); +void istgt_dset64(uint8_t *data, uint64_t value); + +/* random value generation */ +void istgt_gen_random(uint8_t *buf, size_t len); +#ifndef HAVE_SRANDOMDEV +void srandomdev(void); +#endif /* HAVE_SRANDOMDEV */ +#ifndef HAVE_ARC4RANDOM +uint32_t arc4random(void); +#endif /* HAVE_ARC4RANDOM */ + +/* convert from/to bin/hex */ +int istgt_bin2hex(char *buf, size_t len, const uint8_t *data, size_t data_len); +int istgt_hex2bin(uint8_t *data, size_t data_len, const char *str); + +/* other functions */ +void istgt_dump(const char *label, const uint8_t *buf, size_t len); +void istgt_fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len); +void istgt_yield(void); + +void poolinit(void); +void poolfini(void); +int poolprint(char *inbuf, int len); +#endif /* ISTGT_MISC_H */ diff --git a/src/istgt_proto.h b/src/istgt_proto.h new file mode 100644 index 00000000..8f02de01 --- /dev/null +++ b/src/istgt_proto.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_PROTO_H +#define ISTGT_PROTO_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USE_ATOMIC +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MACHINE_ATOMIC_H +#include +#endif +#ifdef HAVE_SYS_ATOMIC_H +#include +#endif +#endif /* USE_ATOMIC */ + + +#include +#include +#include +#ifdef HAVE_UUID_H +#include +#endif +#include "istgt.h" +#include "istgt_iscsi.h" +#include "istgt_lu.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define ISTGT_GNUC_PREREQ(ma,mi) \ + (__GNUC__ > (ma) || (__GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))) +#else +#define ISTGT_GNUC_PREREQ(ma,mi) 0 +#endif + +/* istgt_iscsi.c */ +int istgt_chap_get_authinfo(ISTGT_CHAP_AUTH *auth, const char *authfile, const char *authuser, int ag_tag); +int istgt_iscsi_transfer_out(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, size_t transfer_len); +int istgt_create_sess(ISTGT_Ptr istgt, CONN_Ptr conn, ISTGT_LU_Ptr lu); +int istgt_create_conn(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen); +void istgt_lock_gconns(void); +void istgt_unlock_gconns(void); +int istgt_get_gnconns(void); +CONN_Ptr istgt_get_gconn(int idx); +int istgt_get_active_conns(void); +int istgt_stop_conns(void); +CONN_Ptr istgt_find_conn(const char *initiator_port, const char *target_name, uint16_t tsih); +int istgt_iscsi_init(ISTGT_Ptr istgt); +int istgt_iscsi_shutdown(ISTGT_Ptr istgt); + +/* istgt_lu.c */ +int istgt_lu_allow_netmask(const char *netmask, const char *addr); +void istgt_connection_status(CONN_Ptr conn, const char *status); +int istgt_lu_access(CONN_Ptr conn, ISTGT_LU_Ptr lu, const char *iqn, const char *addr); +int istgt_lu_visible(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu, const char *iqn, int pg_tag); +int istgt_lu_sendtargets(CONN_Ptr conn, const char *iiqn, const char *iaddr, const char *tiqn, uint8_t *data, int alloc_len, int data_len); +ISTGT_LU_Ptr istgt_lu_find_target(ISTGT_Ptr istgt, const char *target_name); +int istgt_lu_add_nexus(ISTGT_LU_Ptr lu, char *initiator_port); +int istgt_lu_remove_nexus(ISTGT_LU_Ptr lu, char *initiator_port); +uint16_t istgt_lu_allocate_tsih(ISTGT_LU_Ptr lu, const char *initiator_port, int tag); +void istgt_lu_free_tsih(ISTGT_LU_Ptr lu, uint16_t tsih, char *initiator_port); +char *istgt_lu_get_media_flags_string(int flags, char *buf, size_t len); +uint64_t istgt_lu_get_devsize(const char *file); +uint64_t istgt_lu_get_filesize(const char *file); +uint64_t istgt_lu_parse_size(const char *size); +int istgt_lu_parse_media_flags(const char *flags); +uint64_t istgt_lu_parse_media_size(const char *file, const char *size, int *flags); +PORTAL_GROUP *istgt_lu_find_portalgroup(ISTGT_Ptr istgt, int tag); +INITIATOR_GROUP *istgt_lu_find_initiatorgroup(ISTGT_Ptr istgt, int tag); +int istgt_lu_init(ISTGT_Ptr istgt); +int istgt_lu_reload_delete(ISTGT_Ptr istgt); +int istgt_lu_reload_update(ISTGT_Ptr istgt); +int istgt_lu_update_ig(ISTGT_Ptr istgt, INITIATOR_GROUP *igp_new); +int istgt_lu_set_all_state(ISTGT_Ptr istgt, ISTGT_STATE state); +int istgt_lu_create_threads(ISTGT_Ptr istgt); +int istgt_lu_shutdown(ISTGT_Ptr istgt); +int istgt_lu_islun2lun(uint64_t islun); +uint64_t istgt_lu_lun2islun(int lun, int maxlun); +int istgt_lu_reset(ISTGT_LU_Ptr lu, uint64_t lun, istgt_ua_type ua_type); +int istgt_lu_reset_all(ISTGT_Ptr istgt, istgt_ua_type ua_type); +ISTGT_LU_TASK_Ptr istgt_lu_create_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int lun, ISTGT_LU_DISK * spec); +int istgt_lu_destroy_task(ISTGT_LU_TASK_Ptr lu_task); +int istgt_lu_clear_task_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu); +int istgt_lu_clear_task_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun); +int istgt_lu_clear_task_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun, uint32_t CmdSN); +int istgt_lu_clear_all_task(ISTGT_LU_Ptr lu, uint64_t lun); + +/* istgt_lu_ctl.c */ +int istgt_create_uctl(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen); +int istgt_uctl_init(ISTGT_Ptr istgt); +int istgt_uctl_shutdown(ISTGT_Ptr istgt); + +/* istgt_lu_disk.c */ +struct istgt_lu_disk_t; +void istgt_scsi_dump_cdb(uint8_t *cdb); +void istgt_strcpy_pad(uint8_t *dst, size_t size, const char *src, int pad); +#ifdef HAVE_UUID_H +uint64_t istgt_uuid2uint64(uuid_t *uuid); +#endif /* HAVE_UUID_H */ +uint64_t istgt_get_lui(const char *name, int lun); +uint64_t istgt_get_rkey(const char *initiator_name, uint64_t lui); +int istgt_lu_set_lid(uint8_t *buf, uint64_t vid); +int istgt_lu_set_id(uint8_t *buf, uint64_t vid); +int istgt_lu_set_extid(uint8_t *buf, uint64_t vid, uint64_t vide); +void istgt_lu_scsi_build_sense_data(ISTGT_LU_CMD_Ptr lu_cmd, int sk, int asc, int ascq); +void istgt_lu_scsi_build_sense_data2(ISTGT_LU_CMD_Ptr lu_cmd, int sk, int asc, int ascq); +int istgt_lu_disk_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_disk_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_disk_modify(ISTGT *istgt, int lun); +int istgt_lu_disk_persist_reservation(ISTGT_LU_Ptr lu, int lun, char *arg); +int istgt_lu_disk_sync_reservation(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_reset(ISTGT_LU_Ptr lu, int lun, istgt_ua_type ua_type); +int istgt_lu_disk_clear_reservation(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_start(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_stop(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_status(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); +int istgt_lu_disk_queue_clear_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu); +int istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun, uint32_t CmdSN); +int istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_queue(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); +int istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu, int *lun); +int istgt_lu_disk_cmd_queue_count(ISTGT_LU_Ptr lu, int *lun); +int istgt_lu_disk_blockedq_count(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_cmdq_count(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu, int lun, int tind); +istgt_task_action istgt_check_for_istgt_queue(ISTGT_QUEUE_Ptr queue, ISTGT_LU_TASK_Ptr unblocked_lu_task); +istgt_task_action istgt_check_for_all_luworkers(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task); +istgt_task_action istgt_check_for_all_maint_luworkers(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task); +istgt_task_action istgt_check_for_parallel_ios(ISTGT_LU_DISK *spec, ISTGT_LU_TASK_Ptr unblocked_lu_task); +int is_maintenance_io(ISTGT_LU_TASK_Ptr task); +void istgt_schedule_blocked_requests(ISTGT_LU_DISK *spec, ISTGT_QUEUE_Ptr cmd, ISTGT_QUEUE_Ptr blocked, int maint); +int istgt_lu_disk_signal_worker(ISTGT_LU_Ptr lu); +void istgt_lu_disk_aio_done(siginfo_t *info); +int istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec, uint8_t *data, int sk, int asc, int ascq); + +int istgt_lu_disk_add_nexus(ISTGT_LU_Ptr lu, int lun, const char * initiator_port); +int istgt_lu_disk_remove_nexus(ISTGT_LU_Ptr lu, int lun, const char * initiator_port); +int istgt_lu_disk_build_ua(istgt_ua_type ua_pending, int *sk, int *asc, int *ascq); +int istgt_lu_disk_busy_excused(int opcode); +IT_NEXUS * istgt_lu_disk_get_nexus(ISTGT_LU_DISK *spec, const char * initiator_port); + + +/* istgt_lu_disk_vbox.c */ +int istgt_lu_disk_vbox_lun_init(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_disk_vbox_lun_shutdown(ISTGT_LU_DISK *spec, ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); + +int istgt_lu_disk_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, size_t len); +int istgt_lu_disk_check_pr(ISTGT_LU_DISK *spec, CONN_Ptr conn, int pr_allow); + +int64_t istgt_lu_disk_read_raw(ISTGT_LU_DISK *spec, void *buf, uint64_t nbytes); + + +/* istgt_lu_dvd.c */ +struct istgt_lu_dvd_t; +int istgt_lu_dvd_media_present(struct istgt_lu_dvd_t *spec); +int istgt_lu_dvd_media_lock(struct istgt_lu_dvd_t *spec); +int istgt_lu_dvd_load_media(struct istgt_lu_dvd_t *spec); +int istgt_lu_dvd_unload_media(struct istgt_lu_dvd_t *spec); +int istgt_lu_dvd_change_media(struct istgt_lu_dvd_t *spec, char *type, char *flags, char *file, char *size); +int istgt_lu_dvd_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_dvd_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_dvd_reset(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_dvd_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); + +/* istgt_lu_tape.c */ +struct istgt_lu_tape_t; +int istgt_lu_tape_media_present(struct istgt_lu_tape_t *spec); +int istgt_lu_tape_media_lock(struct istgt_lu_tape_t *spec); +int istgt_lu_tape_load_media(struct istgt_lu_tape_t *spec); +int istgt_lu_tape_unload_media(struct istgt_lu_tape_t *spec); +int istgt_lu_tape_change_media(struct istgt_lu_tape_t *spec, char *type, char *flags, char *file, char *size); +int istgt_lu_tape_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_tape_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_tape_reset(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_tape_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); + +/* istgt_lu_pass.c */ +int istgt_lu_pass_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_pass_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu); +int istgt_lu_pass_reset(ISTGT_LU_Ptr lu, int lun); +int istgt_lu_pass_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd); + +#ifdef USE_ATOMIC +static inline __attribute__((__always_inline__)) int +istgt_lu_get_state(ISTGT_LU_Ptr lu) +{ + ISTGT_STATE state; +#if defined HAVE_ATOMIC_LOAD_ACQ_INT + state = atomic_load_acq_int((unsigned int *)&lu->state); +#elif defined HAVE_ATOMIC_OR_UINT_NV + state = (int)atomic_or_uint_nv((unsigned int *)&lu->state, 0); +#else +#error "no atomic operation" +#endif + return state; +} +static inline __attribute__((__always_inline__)) void +istgt_lu_set_state(ISTGT_LU_Ptr lu, ISTGT_STATE state) +{ +#if defined HAVE_ATOMIC_STORE_REL_INT + atomic_store_rel_int((unsigned int *)&lu->state, state); +#elif defined HAVE_ATOMIC_SWAP_UINT + (void)atomic_swap_uint((unsigned int *)&lu->state, state); +#if defined HAVE_MEMBAR_PRODUCER + membar_producer(); +#endif +#else +#error "no atomic operation" +#endif +} +#elif defined (USE_GCC_ATOMIC) +/* gcc >= 4.1 builtin functions */ +static inline __attribute__((__always_inline__)) int +istgt_lu_get_state(ISTGT_LU_Ptr lu) +{ + ISTGT_STATE state; + state = __sync_fetch_and_add((unsigned int *)&lu->state, 0); + return state; +} +static inline __attribute__((__always_inline__)) void +istgt_lu_set_state(ISTGT_LU_Ptr lu, ISTGT_STATE state) +{ + ISTGT_STATE state_old; + do { + state_old = __sync_fetch_and_add((unsigned int *)&lu->state, 0); + } while (__sync_val_compare_and_swap((unsigned int *)&lu->state, + state_old, state) != state_old); +#if defined (HAVE_GCC_ATOMIC_SYNCHRONIZE) + __sync_synchronize(); +#endif +} +#else /* !USE_ATOMIC && !USE_GCC_ATOMIC */ +static inline __attribute__((__always_inline__)) int +istgt_lu_get_state(ISTGT_LU_Ptr lu) +{ + ISTGT_STATE state; + MTX_LOCK(&lu->state_mutex); + state = lu->state; + MTX_UNLOCK(&lu->state_mutex); + return state; +} + +static inline __attribute__((__always_inline__)) void +istgt_lu_set_state(ISTGT_LU_Ptr lu, ISTGT_STATE state) +{ + MTX_LOCK(&lu->state_mutex); + lu->state = state; + MTX_UNLOCK(&lu->state_mutex); +} +#endif /* USE_ATOMIC */ + +#endif /* ISTGT_PROTO_H */ diff --git a/src/istgt_queue.c b/src/istgt_queue.c new file mode 100644 index 00000000..38808a0f --- /dev/null +++ b/src/istgt_queue.c @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +#include "istgt_misc.h" +#include "istgt_queue.h" +#include "istgt_lu.h" +#include "istgt_log.h" + +/*Queues are implemented as Circular Doubly Linked Lists*/ +int +istgt_queue_init(ISTGT_QUEUE_Ptr head) +{ + if (head == NULL) + return -1; + head->prev = head; + head->next = head; + head->elem = NULL; + head->num = 0; + return 0; +} + +void +istgt_queue_destroyi(ISTGT_QUEUE_Ptr head, uint16_t line) +{ + ISTGT_QUEUE_Ptr qp; + ISTGT_QUEUE_Ptr next; + + if (head == NULL) + return; + for (qp = head->next; qp != NULL && qp != head; qp = next) { + next = qp->next; + xfreei(qp, line); + } + head->next = head; + head->prev = head; +} + +int +istgt_queue_count(ISTGT_QUEUE_Ptr head) +{ +#if 0 + ISTGT_QUEUE_Ptr qp; + int num; + + if (head == NULL) + return 0; + num = 0; + for (qp = head->next; qp != NULL && qp != head; qp = qp->next) { + num++; + } + return num; +#else + if (head == NULL) + return 0; + return head->num; +#endif +} + +ISTGT_QUEUE_Ptr +istgt_queue_enqueuei(ISTGT_QUEUE_Ptr head, void *elem, uint16_t line) +{ + ISTGT_QUEUE_Ptr qp; + ISTGT_QUEUE_Ptr tail; + + if (head == NULL) + return NULL; + qp = xmalloci(sizeof *qp, line); + qp->num = head->num; + qp->elem = elem; + + tail = head->prev; + if (tail == NULL) { + head->next = qp; + head->prev = qp; + qp->next = head; + qp->prev = head; + } else { + tail->next = qp; + head->prev = qp; + qp->next = head; + qp->prev = tail; + } + head->num++; + return qp; +} + +ISTGT_QUEUE_Ptr +istgt_queue_enqueue_afteri(ISTGT_QUEUE_Ptr head, ISTGT_QUEUE_Ptr current_ptr, void *elem, uint16_t line) +{ + ISTGT_QUEUE_Ptr qp, next_ptr; + + if (head == NULL) + return NULL; + if (current_ptr == NULL) + return NULL; + qp = xmalloci(sizeof *qp, line); + qp->num = current_ptr->num + 1; + qp->elem = elem; + + next_ptr = current_ptr->next; + + if(next_ptr == NULL || next_ptr == current_ptr) { + current_ptr->next = qp; + current_ptr->prev = qp; + qp->next = current_ptr; + qp->prev = current_ptr; + } else { + current_ptr->next = qp; + next_ptr->prev = qp; + qp->next = next_ptr; + qp->prev = current_ptr; + } + head->num++; + return qp; +} + +void * +istgt_queue_dequeuei(ISTGT_QUEUE_Ptr head, uint16_t line) +{ + ISTGT_QUEUE_Ptr first; + ISTGT_QUEUE_Ptr next; + void *elem; + + if (head == NULL) + return NULL; + first = head->next; + if (first == NULL || first == head) { + return NULL; + } else { + elem = first->elem; + next = first->next; + xfreei(first, line); + if (next == NULL) { + head->next = NULL; + head->prev = NULL; + } else { + head->next = next; + next->prev = head; + } + } + head->num--; + return elem; +} + +void * +istgt_queue_dequeue_middlei(ISTGT_QUEUE_Ptr head, ISTGT_QUEUE_Ptr complete_queue_ptr, uint16_t line) +{ + ISTGT_QUEUE_Ptr prev = NULL; + ISTGT_QUEUE_Ptr next = NULL; + if (head == NULL || complete_queue_ptr == NULL || complete_queue_ptr == head) + return NULL; + prev = complete_queue_ptr->prev; + next = complete_queue_ptr->next; + + prev->next = next; + if(next == NULL) + head->prev = NULL; + else + next->prev = prev; + xfreei(complete_queue_ptr, line); + head->num--; + return NULL; +} + +void * +istgt_queue_first(ISTGT_QUEUE_Ptr head) +{ + ISTGT_QUEUE_Ptr first; + void *elem; + + if (head == NULL) + return NULL; + first = head->next; + if (first == NULL || first == head) { + return NULL; + } else { + elem = first->elem; + } + return elem; +} +ISTGT_QUEUE_Ptr +istgt_queue_enqueue_firsti(ISTGT_QUEUE_Ptr head, void *elem, uint16_t line) +{ + ISTGT_QUEUE_Ptr qp; + ISTGT_QUEUE_Ptr first; + + if (head == NULL) + return NULL; + qp = xmalloci(sizeof *qp, line); + qp->num = head->num; + qp->elem = elem; + + first = head->next; + if (first == NULL || first == head) { + head->next = qp; + head->prev = qp; + qp->next = head; + qp->prev = head; + } else { + head->next = qp; + first->prev = qp; + qp->next = first; + qp->prev = head; + } + head->num++; + return qp; +} + +void * +istgt_queue_last(ISTGT_QUEUE_Ptr head, void *elem) +{ + ISTGT_QUEUE_Ptr last; + if (head == NULL) + return NULL; + + last = head->prev; + if (last == NULL || last == head) + return NULL; + else + elem = last->elem; + return elem; +} + +void * +istgt_queue_prev(ISTGT_QUEUE_Ptr head, void * elem) +{ + ISTGT_QUEUE_Ptr qp; + ISTGT_QUEUE_Ptr first; + + if (head == NULL || elem == NULL) + return NULL; + + first = head->next; + + if (first == NULL || first == head ) + return NULL; + + for (qp = head->next; qp != NULL && qp != head; qp = qp->next) { + if (qp == elem) + return qp->prev; + } + return NULL; +} + +ISTGT_QUEUE_Ptr +istgt_get_prev_qptr(void *cookie) +{ + ISTGT_QUEUE_Ptr cp; + if(cookie == NULL) + return NULL; + cp = (ISTGT_QUEUE_Ptr)cookie; + return cp->prev; +} + +ISTGT_QUEUE_Ptr +istgt_get_next_qptr(void *cookie) +{ + ISTGT_QUEUE_Ptr cp; + if(cookie == NULL) + return NULL; + cp = (ISTGT_QUEUE_Ptr)cookie; + return cp->next; +} + +/* + * Queue walk when we do not expect the queue to change + * Uses a cookie at the caller to maintain the position of + * the next element. + * + * Usage: + * void *cookie=NULL; + * while(elem=istgt_queue_walk(some_queue,&cookie)) { + * do_something(elem); + * } + */ +void * +istgt_queue_walk(ISTGT_QUEUE_Ptr head, void ** cookie) +{ + ISTGT_QUEUE_Ptr cp; + + /* Empty queue */ + if (head == NULL) { + *cookie = NULL; + return NULL; + } + + if (head->next == NULL) { + *cookie = NULL; + return NULL; + } + + if (*cookie == head) { + return NULL; + } + + if (head == head->next) { + *cookie = NULL; + return NULL; + } + + if (*cookie == NULL) { + cp = head->next; + } + else { + cp = (ISTGT_QUEUE_Ptr)*cookie; + } + + *cookie = cp->next; + if(unlikely(*cookie == NULL)) + ISTGT_ERRLOG("cookie is NULL!!!!!!\n"); + return *cookie == NULL ? NULL :cp->elem; +} + +void * +istgt_queue_reverse_walk(ISTGT_QUEUE_Ptr head, void ** cookie) +{ + ISTGT_QUEUE_Ptr cp; + + /* Empty queue */ + if (head == NULL) { + *cookie = NULL; + return NULL; + } + + if (head->next == NULL) { + *cookie = NULL; + return NULL; + } + + if (*cookie == head) { + return NULL; + } + + if (head == head->next) { + *cookie = NULL; + return NULL; + } + + if (*cookie == NULL) { + cp = head->prev; + } + else { + cp = (ISTGT_QUEUE_Ptr)*cookie; + } + + *cookie = cp->prev; + if(unlikely(*cookie == NULL)) + ISTGT_ERRLOG("cookie is NULL!!!!!!\n"); + return *cookie == NULL ? NULL :cp->elem; +} + diff --git a/src/istgt_queue.h b/src/istgt_queue.h new file mode 100644 index 00000000..777dca7e --- /dev/null +++ b/src/istgt_queue.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_QUEUE_H +#define ISTGT_QUEUE_H + +#include + +typedef struct istgt_queue_t { + struct istgt_queue_t *prev; + struct istgt_queue_t *next; + void *elem; + int num; +} ISTGT_QUEUE; +typedef ISTGT_QUEUE *ISTGT_QUEUE_Ptr; + +int istgt_queue_init(ISTGT_QUEUE_Ptr head); +#define istgt_queue_destroy(head) istgt_queue_destroyi(head, __LINE__) +void istgt_queue_destroyi(ISTGT_QUEUE_Ptr head, uint16_t line); +int istgt_queue_count(ISTGT_QUEUE_Ptr head); + +#define istgt_queue_enqueue(head, elem) istgt_queue_enqueuei(head, elem, __LINE__) +#define istgt_queue_enqueue_after(head, current_ptr, elem) istgt_queue_enqueue_afteri(head, current_ptr, elem, __LINE__) +#define istgt_queue_dequeue(head) istgt_queue_dequeuei(head, __LINE__) +#define istgt_queue_dequeue_middle(head, ptr) istgt_queue_dequeue_middlei(head, ptr, __LINE__) +#define istgt_queue_enqueue_first(head, elem) istgt_queue_enqueue_firsti(head, elem, __LINE__) + +ISTGT_QUEUE_Ptr istgt_get_next_qptr(void *cookie); +ISTGT_QUEUE_Ptr istgt_get_prev_qptr(void *cookie); +ISTGT_QUEUE_Ptr istgt_queue_enqueuei(ISTGT_QUEUE_Ptr head, void *elem, uint16_t line); +ISTGT_QUEUE_Ptr istgt_queue_enqueue_afteri(ISTGT_QUEUE_Ptr head, ISTGT_QUEUE_Ptr current_ptr, void *elem, uint16_t line); +void *istgt_queue_dequeuei(ISTGT_QUEUE_Ptr head, uint16_t line); +void *istgt_queue_dequeue_middlei(ISTGT_QUEUE_Ptr head, ISTGT_QUEUE_Ptr complete_queue_ptr, uint16_t line); +ISTGT_QUEUE_Ptr istgt_queue_enqueue_firsti(ISTGT_QUEUE_Ptr head, void *elem, uint16_t line); + +void *istgt_queue_first(ISTGT_QUEUE_Ptr head); +void *istgt_queue_last(ISTGT_QUEUE_Ptr head, void *elem); +void *istgt_queue_prev(ISTGT_QUEUE_Ptr head, void *elem); +void * istgt_queue_walk(ISTGT_QUEUE_Ptr head, void ** cookie); +void * istgt_queue_reverse_walk(ISTGT_QUEUE_Ptr head, void ** cookie); + +#endif /* ISTGT_QUEUE_H */ + +#ifdef __linux__ +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif diff --git a/src/istgt_scsi.h b/src/istgt_scsi.h new file mode 100644 index 00000000..041754b2 --- /dev/null +++ b/src/istgt_scsi.h @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2008-2011 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_SCSI_H +#define ISTGT_SCSI_H + +typedef enum { + ISTGT_SCSI_STATUS_GOOD = 0x00, + ISTGT_SCSI_STATUS_CHECK_CONDITION = 0x02, + ISTGT_SCSI_STATUS_CONDITION_MET = 0x04, + ISTGT_SCSI_STATUS_BUSY = 0x08, + ISTGT_SCSI_STATUS_INTERMEDIATE = 0x10, + ISTGT_SCSI_STATUS_INTERMEDIATE_CONDITION_MET = 0x14, + ISTGT_SCSI_STATUS_RESERVATION_CONFLICT = 0x18, + ISTGT_SCSI_STATUS_Obsolete = 0x22, + ISTGT_SCSI_STATUS_TASK_SET_FULL = 0x28, + ISTGT_SCSI_STATUS_ACA_ACTIVE = 0x30, + ISTGT_SCSI_STATUS_TASK_ABORTED = 0x40, +} ISTGT_SCSI_STATUS; + +typedef enum { + ISTGT_SCSI_SENSE_NO_SENSE = 0x00, + ISTGT_SCSI_SENSE_RECOVERED_ERROR =0x01, + ISTGT_SCSI_SENSE_NOT_READY = 0x02, + ISTGT_SCSI_SENSE_MEDIUM_ERROR = 0x03, + ISTGT_SCSI_SENSE_HARDWARE_ERROR = 0x04, + ISTGT_SCSI_SENSE_ILLEGAL_REQUEST = 0x05, + ISTGT_SCSI_SENSE_UNIT_ATTENTION = 0x06, + ISTGT_SCSI_SENSE_DATA_PROTECT = 0x07, + ISTGT_SCSI_SENSE_BLANK_CHECK = 0x08, + ISTGT_SCSI_SENSE_VENDOR_SPECIFIC = 0x09, + ISTGT_SCSI_SENSE_COPY_ABORTED = 0x0a, + ISTGT_SCSI_SENSE_ABORTED_COMMAND = 0x0b, + ISTGT_SCSI_SENSE_VOLUME_OVERFLOW = 0x0d, + ISTGT_SCSI_SENSE_MISCOMPARE = 0x0e, +} ISTGT_SCSI_SENSE; + +typedef enum { + /* SPC3 related */ + SPC_ACCESS_CONTROL_IN = 0x86, + SPC_ACCESS_CONTROL_OUT = 0x87, + //SPC_CHANGE_ALIASES = 0x000b00a4, + SPC_EXTENDED_COPY = 0x83, + SPC_INQUIRY = 0x12, + SPC_LOG_SELECT = 0x4c, + SPC_LOG_SENSE = 0x4d, + SPC_MODE_SELECT_6 = 0x15, + SPC_MODE_SELECT_10 = 0x55, + SPC_MODE_SENSE_6 = 0x1a, + SPC_MODE_SENSE_10 = 0x5a, + SPC_PERSISTENT_RESERVE_IN = 0x5e, + SPC_PERSISTENT_RESERVE_OUT = 0x5f, + SPC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + SPC_READ_ATTRIBUTE = 0x8c, + SPC_READ_BUFFER = 0x3c, + //SPC_READ_MEDIA_SERIAL_NUMBER = 0x000100ab, + SPC_RECEIVE_COPY_RESULTS = 0x84, + SPC_RECEIVE_DIAGNOSTIC_RESULTS = 0x1c, + //SPC_REPORT_ALIASES = 0x000b00a3, + //SPC_REPORT_DEVICE_IDENTIFIER = 0x000500a3, + SPC_REPORT_LUNS = 0xa0, + //SPC_REPORT_PRIORITY = 0x000e00a3, + //SPC_REPORT_SUPPORTED_OPERATION_CODES = 0x000c00a3, + //SPC_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS = 0x000d00a3, + //SPC_REPORT_TARGET_PORT_GROUPS = 0x000a00a3, + //SPC_REPORT_TIMESTAMP = 0x000f00a3, + SPC_REQUEST_SENSE = 0x03, + SPC_SEND_DIAGNOSTIC = 0x1d, + //SPC_SET_DEVICE_IDENTIFIER = 0x000600a4, + //SPC_SET_PRIORITY = 0x000e00a4, + //SPC_SET_TARGET_PORT_GROUPS = 0x000a00a4, + //SPC_SET_TIMESTAMP = 0x000f00a4, + SPC_TEST_UNIT_READY = 0x00, + SPC_WRITE_ATTRIBUTE = 0x8d, + SPC_WRITE_BUFFER = 0x3b, + + SPC_SERVICE_ACTION_IN_12 = 0xab, + SPC_SERVICE_ACTION_OUT_12 = 0xa9, + SPC_SERVICE_ACTION_IN_16 = 0x9e, + SPC_SERVICE_ACTION_OUT_16 = 0x9f, + + SPC_VARIABLE_LENGTH = 0x7f, + + SPC_MO_CHANGE_ALIASES = 0x0b, + SPC_MO_SET_DEVICE_IDENTIFIER = 0x06, + SPC_MO_SET_PRIORITY = 0x0e, + SPC_MO_SET_TARGET_PORT_GROUPS = 0x0a, + SPC_MO_SET_TIMESTAMP = 0x0f, + SPC_MI_REPORT_ALIASES = 0x0b, + SPC_MI_REPORT_DEVICE_IDENTIFIER = 0x05, + SPC_MI_REPORT_PRIORITY = 0x0e, + SPC_MI_REPORT_SUPPORTED_OPERATION_CODES = 0x0c, + SPC_MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS = 0x0d, + SPC_MI_REPORT_TARGET_PORT_GROUPS = 0x0a, + SPC_MI_REPORT_TIMESTAMP = 0x0f, + + /* SPC2 related (Obsolete) */ + SPC2_RELEASE_6 = 0x17, + SPC2_RELEASE_10 = 0x57, + SPC2_RESERVE_6 = 0x16, + SPC2_RESERVE_10 = 0x56, +} SPC_OPCODE; + +typedef enum { + SCC_MAINTENANCE_IN = 0xa3, + SCC_MAINTENANCE_OUT = 0xa4, +} SCC_OPCODE; + +typedef enum { + SBC_COMPARE_AND_WRITE = 0x89, + SBC_FORMAT_UNIT = 0x04, + SBC_GET_LBA_STATUS = 0x0012009e, + SBC_ORWRITE_16 = 0x8b, + //SBC_ORWRITE_32 = 0x000e007f, + SBC_PRE_FETCH_10 = 0x34, + SBC_PRE_FETCH_16 = 0x90, + SBC_READ_6 = 0x08, + SBC_READ_10 = 0x28, + SBC_READ_12 = 0xa8, + SBC_READ_16 = 0x88, + //SBC_READ_32 = 0x0009007f, + SBC_READ_ATTRIBUTE = 0x8c, + SBC_READ_BUFFER = 0x3c, + SBC_READ_CAPACITY_10 = 0x25, + //SBC_READ_CAPACITY_16 = 0x0010009e, + SBC_READ_DEFECT_DATA_10 = 0x37, + SBC_READ_DEFECT_DATA_12 = 0xb7, + SBC_READ_LONG_10 = 0x3e, + //SBC_READ_LONG_16 = 0x0011009e, + SBC_REASSIGN_BLOCKS = 0x07, + //SBC_REPORT_REFERRALS = 0x0013009e, + SBC_SANITIZE = 0x48, + SBC_START_STOP_UNIT = 0x1b, + SBC_SYNCHRONIZE_CACHE_10 = 0x35, + SBC_SYNCHRONIZE_CACHE_16 = 0x91, + SBC_UNMAP = 0x42, + SBC_VERIFY_10 = 0x2f, + SBC_VERIFY_12 = 0xaf, + SBC_VERIFY_16 = 0x8f, + //SBC_VERIFY_32 = 0x000a007f, + SBC_WRITE_6 = 0x0a, + SBC_WRITE_10 = 0x2a, + SBC_WRITE_12 = 0xaa, + SBC_WRITE_16 = 0x8a, + //SBC_WRITE_32 = 0x000b007f, + SBC_WRITE_AND_VERIFY_10 = 0x2e, + SBC_WRITE_AND_VERIFY_12 = 0xae, + SBC_WRITE_AND_VERIFY_16 = 0x8e, + //SBC_WRITE_AND_VERIFY_32 = 0x000c007f, + SBC_WRITE_LONG_10 = 0x3f, + //SBC_WRITE_LONG_16 = 0x0011009f, + SBC_WRITE_SAME_10 = 0x41, + SBC_WRITE_SAME_16 = 0x93, + //SBC_WRITE_SAME_32 = 0x000d007f, + SBC_XDREAD_10 = 0x52, + //SBC_XDREAD_32 = 0x0003007f, + SBC_XDWRITE_10 = 0x50, + //SBC_XDWRITE_32 = 0x0004007f, + SBC_XDWRITEREAD_10 = 0x53, + //SBC_XDWRITEREAD_32 = 0x0007007f, + SBC_XPWRITE_10 = 0x51, + //SBC_XPWRITE_32 = 0x0006007f, + + SBC_SAI_READ_CAPACITY_16 = 0x10, + SBC_SAI_READ_LONG_16 = 0x11, + SBC_SAO_WRITE_LONG_16 = 0x11, + + SBC_VL_READ_32 = 0x0009, + SBC_VL_VERIFY_32 = 0x000a, + SBC_VL_WRITE_32 = 0x000b, + SBC_VL_WRITE_AND_VERIFY_32 = 0x000c, + SBC_VL_WRITE_SAME_32 = 0x000d, + SBC_VL_XDREAD_32 = 0x0003, + SBC_VL_XDWRITE_32 = 0x0004, + SBC_VL_XDWRITEREAD_32 = 0x0007, + SBC_VL_XPWRITE_32 = 0x0006, +} SBC_OPCODE; + +typedef enum { + /* MMC6 */ + MMC_READ_DISC_STRUCTURE = 0xad, + + /* MMC4 */ + MMC_BLANK = 0xa1, + MMC_CLOSE_TRACK_SESSION = 0x5b, + MMC_ERASE_10 = 0x2c, + MMC_FORMAT_UNIT = 0x04, + MMC_GET_CONFIGURATION = 0x46, + MMC_GET_EVENT_STATUS_NOTIFICATION = 0x4a, + MMC_GET_PERFORMANCE = 0xac, + MMC_INQUIRY = 0x12, + MMC_LOAD_UNLOAD_MEDIUM = 0xa6, + MMC_MECHANISM_STATUS = 0xbd, + MMC_MODE_SELECT_10 = 0x55, + MMC_MODE_SENSE_10 = 0x5a, + MMC_PAUSE_RESUME = 0x4b, + MMC_PLAY_AUDIO_10 = 0x45, + MMC_PLAY_AUDIO_12 = 0xa5, + MMC_PLAY_AUDIO_MSF = 0x47, + MMC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + MMC_READ_10 = 0x28, + MMC_READ_12 = 0xa8, + MMC_READ_BUFFER = 0x3c, + MMC_READ_BUFFER_CAPACITY = 0x5c, + MMC_READ_CAPACITY = 0x25, + MMC_READ_CD = 0xbe, + MMC_READ_CD_MSF = 0xb9, + MMC_READ_DISC_INFORMATION = 0x51, + MMC_READ_DVD_STRUCTURE = 0xad, + MMC_READ_FORMAT_CAPACITIES = 0x23, + MMC_READ_SUB_CHANNEL = 0x42, + MMC_READ_TOC_PMA_ATIP = 0x43, + MMC_READ_TRACK_INFORMATION = 0x52, + MMC_REPAIR_TRACK = 0x58, + MMC_REPORT_KEY = 0xa4, + MMC_REQUEST_SENSE = 0x03, + MMC_RESERVE_TRACK = 0x53, + MMC_SCAN = 0xba, + MMC_SEEK_10 = 0x2b, + MMC_SEND_CUE_SHEET = 0x5d, + MMC_SEND_DVD_STRUCTURE = 0xbf, + MMC_SEND_KEY = 0xa3, + MMC_SEND_OPC_INFORMATION = 0x54, + MMC_SET_CD_SPEED = 0xbb, + MMC_SET_READ_AHEAD = 0xa7, + MMC_SET_STREAMING = 0xb6, + MMC_START_STOP_UNIT = 0x1b, + MMC_STOP_PLAY_SCAN = 0x4e, + MMC_SYNCHRONIZE_CACHE = 0x35, + MMC_TEST_UNIT_READY = 0x00, + MMC_VERIFY_10 = 0x2f, + MMC_WRITE_10 = 0xa2, + MMC_WRITE_12 = 0xaa, + MMC_WRITE_AND_VERIFY_10 = 0x2e, + MMC_WRITE_BUFFER = 0x3b, +} MMC_OPCODE; + +typedef enum { + SSC_ERASE_6 = 0x19, + SSC_FORMAT_MEDIUM = 0x04, + SSC_LOAD_UNLOAD = 0x1b, + SSC_LOCATE_10 = 0x2b, + SSC_LOCATE_16 = 0x92, + SSC_MOVE_MEDIUM_ATTACHED = 0xa7, + SSC_READ_6 = 0x08, + SSC_READ_BLOCK_LIMITS = 0x05, + SSC_READ_ELEMENT_STATUS_ATTACHED = 0xb4, + SSC_READ_POSITION = 0x34, + SSC_READ_REVERSE_6 = 0x0f, + SSC_RECOVER_BUFFERED_DATA = 0x14, + SSC_REPORT_DENSITY_SUPPORT = 0x44, + SSC_REWIND = 0x01, + SSC_SET_CAPACITY = 0x0b, + SSC_SPACE_6 = 0x11, + SSC_SPACE_16 = 0x91, + SSC_VERIFY_6 = 0x13, + SSC_WRITE_6 = 0x0a, + SSC_WRITE_FILEMARKS_6 = 0x10, +} SSC_OPCODE; + +typedef enum { + SPC_VPD_DEVICE_IDENTIFICATION = 0x83, + SPC_VPD_EXTENDED_INQUIRY_DATA = 0x86, + SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES = 0x85, + SPC_VPD_MODE_PAGE_POLICY = 0x87, + SPC_VPD_SCSI_PORTS = 0x88, + SPC_VPD_SOFTWARE_INTERFACE_IDENTIFICATION = 0x84, + SPC_VPD_SUPPORTED_VPD_PAGES = 0x00, + SPC_VPD_UNIT_SERIAL_NUMBER = 0x80, +} SPC_VPD; + +enum { + SPC_PERIPHERAL_DEVICE_TYPE_DISK = 0x00, + SPC_PERIPHERAL_DEVICE_TYPE_TAPE = 0x01, + SPC_PERIPHERAL_DEVICE_TYPE_DVD = 0x05, + SPC_PERIPHERAL_DEVICE_TYPE_CHANGER = 0x08, + + SPC_VERSION_NONE = 0x00, + SPC_VERSION_SPC = 0x03, + SPC_VERSION_SPC2 = 0x04, + SPC_VERSION_SPC3 = 0x05, + SPC_VERSION_SPC4 = 0x06, + + SPC_PROTOCOL_IDENTIFIER_FC = 0x00, + SPC_PROTOCOL_IDENTIFIER_PSCSI = 0x01, + SPC_PROTOCOL_IDENTIFIER_SSA = 0x02, + SPC_PROTOCOL_IDENTIFIER_IEEE1394 = 0x03, + SPC_PROTOCOL_IDENTIFIER_RDMA = 0x04, + SPC_PROTOCOL_IDENTIFIER_ISCSI = 0x05, + SPC_PROTOCOL_IDENTIFIER_SAS = 0x06, + SPC_PROTOCOL_IDENTIFIER_ADT = 0x07, + SPC_PROTOCOL_IDENTIFIER_ATA = 0x08, + + SPC_VPD_CODE_SET_BINARY = 0x01, + SPC_VPD_CODE_SET_ASCII = 0x02, + SPC_VPD_CODE_SET_UTF8 = 0x03, + + SPC_VPD_ASSOCIATION_LOGICAL_UNIT = 0x00, + SPC_VPD_ASSOCIATION_TARGET_PORT = 0x01, + SPC_VPD_ASSOCIATION_TARGET_DEVICE = 0x02, + + SPC_VPD_IDENTIFIER_TYPE_VENDOR_SPECIFIC = 0x00, + SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID = 0x01, + SPC_VPD_IDENTIFIER_TYPE_EUI64 = 0x02, + SPC_VPD_IDENTIFIER_TYPE_NAA = 0x03, + SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT = 0x04, + SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP = 0x05, + SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP = 0x06, + SPC_VPD_IDENTIFIER_TYPE_MD5_LOGICAL_UNIT = 0x07, + SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME = 0x08, +}; + +#endif /* ISTGT_SCSI_H */ diff --git a/src/istgt_ser_table.c b/src/istgt_ser_table.c new file mode 100644 index 00000000..a98234b9 --- /dev/null +++ b/src/istgt_ser_table.c @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2003 Silicon Graphics International Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_ser_table.c#1 $ + * $FreeBSD: stable/9/sys/cam/ctl/ctl_ser_table.c 229997 2012-01-12 00:34:33Z ken $ + */ + +/* + * iSCSI Target command serialization table. + * + * Author: Kim Le + */ + +/****************************************************************************/ +/* TABLE istgtSerTbl */ +/* */ +/* The matrix which drives the serialization algorithm. The major index */ +/* (the first) into this table is the command being checked and the minor */ +/* index is the command against which the first command is being checked. */ +/* i.e., the major index (row) command is ahead of the minor index command */ +/* (column) in the queue. This allows the code to optimize by capturing */ +/* the result of the first indexing operation into a pointer. */ +/* */ +/* Whenever a new value is added to the IDX_T type, this matrix must be */ +/* expanded by one row AND one column -- Because of this, some effort */ +/* should be made to re-use the indexes whenever possible. */ +/* */ +/****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include +#include + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_log.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_md5.h" +#include "istgt_lu.h" +#include "istgt_iscsi.h" +#include "istgt_proto.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +#define sK ISTGT_SER_SKIP /* Skip */ +#define pS ISTGT_SER_PASS /* pS */ +#define bK ISTGT_SER_BLOCK /* Blocked */ +#define xT ISTGT_SER_EXTENT /* Extent check */ + +istgt_serialize_action +istgt_serialize_table[ISTGT_SERIDX_COUNT + 1][ISTGT_SERIDX_COUNT + 1] = { +/**>IDX_ :: 2nd:TUR RD WRT UNMP MDSN MDSL RQSN INQ RDCP RES REL LSNS FMT STR PRIN PROT MAININ INVLD*/ +/*TUR */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, bK, bK, pS, pS, pS, bK, bK, pS, pS}, +/*READ */{ pS, pS, xT, bK, bK, bK, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*WRITE */{ pS, xT, xT, bK, bK, bK, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*UNMAP */{ pS, bK, bK, pS, bK, bK, bK, pS, pS, bK, bK, pS, bK, bK, pS, bK, bK, pS}, +/*MD_SNS */{ pS, bK, bK, bK, pS, bK, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*MD_SEL */{ pS, bK, bK, bK, bK, bK, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*RQ_SNS */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS}, +/*INQ */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS}, +/*RD_CAP */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*RESV */{ bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*REL */{ bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*LOG_SNS */{ pS, pS, pS, pS, pS, bK, bK, pS, pS, bK, bK, pS, bK, bK, bK, bK, bK, pS}, +/*FORMAT */{ pS, bK, bK, bK, bK, bK, pS, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*START */{ pS, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*PRES_IN */{ bK, bK, bK, pS, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*PRES_OUT*/{ bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS}, +/*MAIN_IN */{ pS, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK, bK, bK, bK, pS, pS}, +/*INVLD */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS} +}; + diff --git a/src/istgt_sock.c b/src/istgt_sock.c new file mode 100644 index 00000000..f31cfa74 --- /dev/null +++ b/src/istgt_sock.c @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "istgt.h" +#include "istgt_log.h" +#include "istgt_sock.h" +#include "istgt_misc.h" + +//#define USE_POLLWAIT +#undef USE_POLLWAIT +#define TIMEOUT_RW 60 +#define POLLWAIT 1000 +#define PORTNUMLEN 32 + +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV 0 +#endif + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +int +istgt_getaddr(int sock, char *saddr, int slen, char *caddr, int clen, + uint32_t *iaddr, uint16_t *iport) +{ + struct sockaddr_storage sa; + socklen_t salen; + int rc; + *iaddr = 0; + *iport = 0; + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getsockname(sock, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + ISTGT_ERRLOG("getsockname() failed (errno=%d)\n", errno); + return -1; + } + rc = getnameinfo((struct sockaddr *) &sa, salen, + saddr, slen, NULL, 0, NI_NUMERICHOST); + if (rc != 0) { + ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno); + return -1; + } + + memset(&sa, 0, sizeof sa); + salen = sizeof sa; + rc = getpeername(sock, (struct sockaddr *) &sa, &salen); + if (rc != 0) { + ISTGT_ERRLOG("getpeername() failed (errno=%d)\n", errno); + return -1; + } + if (salen >= sizeof (struct sockaddr_in)) { + *iaddr = ((struct sockaddr_in *)&sa)->sin_addr.s_addr; + *iport = ((struct sockaddr_in *)&sa)->sin_port; + } + rc = getnameinfo((struct sockaddr *) &sa, salen, + caddr, clen, NULL, 0, NI_NUMERICHOST); + if (rc != 0) { + ISTGT_ERRLOG("getnameinfo() failed (errno=%d)\n", errno); + return -1; + } + + return 0; +} +int +istgt_listen_unx(const char *lpath, int que) +{ + /* open a UNIX socket */ + struct sockaddr_un sun; + int local_s = socket(AF_UNIX, SOCK_STREAM, 0); + if (que < 2) + que = 2; + else if (que > 127) + que = 127; + + if (local_s == -1) { + ISTGT_ERRLOG("uctl_listen_unx AF_UNIX socket failed %s (errno=%d)\n", lpath, errno); + return -1; + } + memset(&sun, 0, sizeof(struct sockaddr_un)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, lpath, sizeof(sun.sun_path)); + unlink(sun.sun_path); + if (bind(local_s, (struct sockaddr *)&sun, SUN_LEN(&sun)) != 0) { + ISTGT_ERRLOG("uctl_listen_unx failed to bind %s (errno=%d)\n", lpath, errno); + close(local_s); + return -2; + } + if (listen(local_s, que) != 0) { + ISTGT_ERRLOG("uctl_listen_unx failed to listen at %s (errno=%d)\n", lpath, errno); + close(local_s); + return -3; + } + return local_s; +} +int +istgt_listen(const char *ip, int port, int que) +{ + char buf[MAX_TMPBUF]; + char portnum[PORTNUMLEN]; + char *p; + struct addrinfo hints, *res, *res0; + int sock; + int val = 1; + int rc; + + if (ip == NULL) + return -1; + if (ip[0] == '[') { + strlcpy(buf, ip + 1, sizeof buf); + p = strchr(buf, ']'); + if (p != NULL) + *p = '\0'; + ip = (const char *) &buf[0]; + if (strcasecmp(ip, "*") == 0) { + strlcpy(buf, "::", sizeof buf); + ip = (const char *) &buf[0]; + } + } else { + if (strcasecmp(ip, "*") == 0) { + strlcpy(buf, "0.0.0.0", sizeof buf); + ip = (const char *) &buf[0]; + } + } + snprintf(portnum, sizeof portnum, "%d", port); + memset(&hints, 0, sizeof hints); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + hints.ai_flags |= AI_PASSIVE; + hints.ai_flags |= AI_NUMERICHOST; + rc = getaddrinfo(ip, portnum, &hints, &res0); + if (rc != 0) { + ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno); + return -1; + } + if (que < 2) + que = 2; + else if (que > 255) + que = 255; + + /* try listen */ + sock = -1; + for (res = res0; res != NULL; res = res->ai_next) { + retry: + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + /* error */ + continue; + } + rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val); + if (rc != 0) { + /* error */ + continue; + } + rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val); + if (rc != 0) { + /* error */ + continue; + } + rc = bind(sock, res->ai_addr, res->ai_addrlen); + if (rc == -1 && errno == EINTR) { + /* interrupted? */ + close(sock); + sock = -1; + goto retry; + } + if (rc != 0) { + /* try next family */ + close(sock); + sock = -1; + continue; + } + /* bind OK */ + rc = listen(sock, que); + if (rc != 0) { + close(sock); + sock = -1; + break; + } + break; + } + freeaddrinfo(res0); + + if (sock < 0) { + return -1; + } + return sock; +} + +int +istgt_connect_unx(const char *lpath) +{ + /* open a UNIX socket */ + struct sockaddr_un sun; + int local_s = socket(AF_UNIX, SOCK_STREAM, 0); + memset(&sun, 0, sizeof(struct sockaddr_un)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, lpath, sizeof(sun.sun_path)); + if (connect(local_s, (struct sockaddr *)&sun, SUN_LEN(&sun)) != 0) { + ISTGT_ERRLOG("uctl_connect_unx failed to %s (errno=%d)\n", lpath, errno); + close(local_s); + return -1; + } + return local_s; +} + +int +istgt_connect(const char *host, int port) +{ + char buf[MAX_TMPBUF]; + char portnum[PORTNUMLEN]; + char *p; + struct addrinfo hints, *res, *res0; + int sock; + int val = 1; + int rc; + + if (host == NULL) + return -1; + if (host[0] == '[') { + strlcpy(buf, host + 1, sizeof buf); + p = strchr(buf, ']'); + if (p != NULL) + *p = '\0'; + host = (const char *) &buf[0]; + if (strcasecmp(host, "*") == 0) { + strlcpy(buf, "::", sizeof buf); + host = (const char *) &buf[0]; + } + } else { + if (strcasecmp(host, "*") == 0) { + strlcpy(buf, "0.0.0.0", sizeof buf); + host = (const char *) &buf[0]; + } + } + snprintf(portnum, sizeof portnum, "%d", port); + memset(&hints, 0, sizeof hints); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + rc = getaddrinfo(host, portnum, &hints, &res0); + if (rc != 0) { + ISTGT_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno); + return -1; + } + + /* try connect */ + sock = -1; + for (res = res0; res != NULL; res = res->ai_next) { + retry: + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + /* error */ + continue; + } + rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val); + if (rc != 0) { + /* error */ + continue; + } + rc = connect(sock, res->ai_addr, res->ai_addrlen); + if (rc == -1 && errno == EINTR) { + /* interrupted? */ + close(sock); + sock = -1; + goto retry; + } + if (rc != 0) { + /* try next family */ + close(sock); + sock = -1; + continue; + } + /* connect OK */ + break; + } + freeaddrinfo(res0); + + if (sock < 0) { + return -1; + } + return sock; +} + +int +istgt_set_recvtimeout(int s, int msec) +{ + struct timeval tv; + int rc; + + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + rc = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); + if (rc != 0) + return -1; + return 0; +} + +int +istgt_set_sendtimeout(int s, int msec) +{ + struct timeval tv; + int rc; + + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + rc = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); + if (rc != 0) + return -1; + return 0; +} + +int +istgt_set_recvlowat(int s, int nbytes) +{ + int val; + int rc; + + val = nbytes; + rc = setsockopt(s, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val); + if (rc != 0) + return -1; + return 0; +} + +#ifdef USE_POLLWAIT +static int +can_read_socket(int s, int msec) +{ + struct pollfd fds[1]; + int rc; + + fds[0].fd = s; + fds[0].events = POLLIN; + retry: + do { + rc = poll(fds, 1, msec); + } while (rc == -1 && errno == EINTR); + if (rc == -1 && errno == EAGAIN) { + goto retry; + } + if (rc < 0) { + /* error */ + return -1; + } + if (fds[0].revents & POLLIN) { + /* read OK */ + return 1; + } + return 0; +} + +static int +can_write_socket(int s, int msec) +{ + struct pollfd fds[1]; + int rc; + + fds[0].fd = s; + fds[0].events = POLLOUT; + retry: + do { + rc = poll(fds, 1, msec); + } while (rc == -1 && errno == EINTR); + if (rc == -1 && errno == EAGAIN) { + goto retry; + } + if (rc < 0) { + /* error */ + return -1; + } + if (fds[0].revents & POLLOUT) { + /* write OK */ + return 1; + } + return 0; +} +#endif /* USE_POLLWAIT */ + +#ifdef USE_POLLWAIT +#define UNUSED_POLLWAIT(x) x +#else +#define UNUSED_POLLWAIT(x) x __attribute__((__unused__)) +#endif + +ssize_t +istgt_read_socket(int s, void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout)) +{ + ssize_t n; +#ifdef USE_POLLWAIT + int msec = POLLWAIT; + int rc; +#endif /* USE_POLLWAIT */ + + if (nbytes == 0) + return 0; + +#ifdef USE_POLLWAIT + msec = timeout * 1000; + rc = can_read_socket(s, msec); + if (rc < 0) { + return -1; + } + if (rc == 0) { + /* TIMEOUT */ + return -2; + } + retry: + do { + n = read(s, buf, nbytes); + } while (n == -1 && errno == EINTR); + if (n == -1 && errno == EAGAIN) { + goto retry; + } + if (n < 0) { + return -1; + } +#else + do { + n = recv(s, buf, nbytes, 0); + } while (n == -1 && errno == EINTR); + if (n == -1 && errno == EAGAIN) { + /* TIMEOUT */ + return -2; + } + if (n == -1) { + return -1; + } +#endif /* USE_POLLWAIT */ + return n; +} + +ssize_t +istgt_write_socket(int s, const void *buf, size_t nbytes, int UNUSED_POLLWAIT(timeout)) +{ + ssize_t n; +#ifdef USE_POLLWAIT + int msec = POLLWAIT; + int rc; +#endif /* USE_POLLWAIT */ + + if (nbytes == 0) + return 0; + +#ifdef USE_POLLWAIT + msec = timeout * 1000; + rc = can_write_socket(s, msec); + if (rc < 0) { + return -1; + } + if (rc == 0) { + /* TIMEOUT */ + return -2; + } + retry: + do { + n = write(s, buf, nbytes); + } while (n == -1 && errno == EINTR); + if (n == -1 && errno == EAGAIN) { + goto retry; + } + if (n < 0) { + ISTGT_ERRLOG("write() failed\n"); + return -1; + } +#else + do { + n = send(s, buf, nbytes, 0); + } while (n == -1 && (errno == EINTR || errno == EAGAIN)); + if (n == -1) { + return -1; + } +#endif /* USE_POLLWAIT */ + return n; +} + +ssize_t +istgt_readline_socket(int sock, char *buf, size_t size, char *tmp, size_t tmpsize, int *tmpidx, int *tmpcnt, int timeout) +{ + unsigned char *up, *utp; + ssize_t maxsize; + ssize_t total; + ssize_t n; + int got_cr; + int idx, cnt; + int ch; + + if (size < 2) { + return -1; + } + + up = (unsigned char *) buf; + utp = (unsigned char *) tmp; + maxsize = size - 2; /* LF + NUL */ + total = 0; + idx = *tmpidx; + cnt = *tmpcnt; + got_cr = 0; + + /* receive with LF */ + while (total < maxsize) { + /* fill temporary buffer */ + if (idx == cnt) { + *tmpidx = idx; + up[total] = '\0'; + n = istgt_read_socket(sock, tmp, tmpsize, timeout); + if (n < 0) { + if (total != 0) { + up[total] = '\0'; + return total; + } + return -1; + } + if (n == 0) { + /* EOF */ + up[total] = '\0'; + return total; + } + /* got n bytes */ + cnt = *tmpcnt = n; + idx = 0; + } + + /* copy from temporary until LF */ + ch = utp[idx++]; + if (got_cr && ch != '\n') { + /* CR only */ + /* back to temporary */ + idx--; + /* remove CR */ + total--; + break; + } else if (ch == '\n') { + if (got_cr) { + /* CRLF */ + /* remove CR */ + total--; + } else { + /* LF only */ + } + break; + } else if (ch == '\r') { + got_cr = 1; + } + up[total++] = ch; + } + *tmpidx = idx; + /* always append LF + NUL */ + up[total++] = '\n'; + up[total] = '\0'; + return total; +} + +static ssize_t +istgt_allwrite_socket(int s, const void *buf, size_t nbytes, int timeout) +{ + const uint8_t *cp; + size_t total; + ssize_t n; + + total = 0; + cp = (const uint8_t *) buf; + do { + n = istgt_write_socket(s, cp + total, (nbytes - total), timeout); + if (n < 0) { + return n; + } + total += n; + } while (total < nbytes); + return total; +} + +ssize_t +istgt_writeline_socket(int sock, const char *buf, int timeout) +{ + const unsigned char *up; + ssize_t total; + ssize_t n; + int idx; + int ch; + + up = (const unsigned char *) buf; + total = 0; + idx = 0; + + if (up[0] == '\0') { + /* empty string */ + n = istgt_allwrite_socket(sock, "\r\n", 2, timeout); + if (n < 0) { + return -1; + } + if (n != 2) { + return -1; + } + total = n; + return total; + } + + /* send with CRLF */ + while ((ch = up[idx]) != '\0') { + if (ch == '\r') { + if (up[idx + 1] == '\n') { + /* CRLF */ + n = istgt_allwrite_socket(sock, up, idx + 2, timeout); + if (n < 0) { + return -1; + } + if (n != idx + 2) { + return -1; + } + idx += 2; + } else { + /* CR Only */ + n = istgt_allwrite_socket(sock, up, idx, timeout); + if (n < 0) { + return -1; + } + if (n != idx) { + return -1; + } + idx += 1; + n = istgt_allwrite_socket(sock, "\r\n", 2, timeout); + if (n < 0) { + return -1; + } + if (n != 2) { + return -1; + } + } + } else if (ch == '\n') { + /* LF Only */ + n = istgt_allwrite_socket(sock, up, idx, timeout); + if (n < 0) { + return -1; + } + if (n != idx) { + return -1; + } + idx += 1; + n = istgt_allwrite_socket(sock, "\r\n", 2, timeout); + if (n < 0) { + return -1; + } + if (n != 2) { + return -1; + } + } else { + idx++; + continue; + } + up += idx; + total += idx; + idx = 0; + } + + if (idx != 0) { + /* no CRLF string */ + n = istgt_allwrite_socket(sock, up, idx, timeout); + if (n < 0) { + return -1; + } + if (n != idx) { + return -1; + } + n = istgt_allwrite_socket(sock, "\r\n", 2, timeout); + if (n < 0) { + return -1; + } + if (n != 2) { + return -1; + } + up += idx; + total += idx + 2; + idx = 0; + } + + return total; +} diff --git a/src/istgt_sock.h b/src/istgt_sock.h new file mode 100644 index 00000000..3db4a465 --- /dev/null +++ b/src/istgt_sock.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_SOCK_H +#define ISTGT_SOCK_H + +#include +#include + +int istgt_getaddr(int sock, char *saddr, int slen, char *caddr, int clen, uint32_t *iaddr, uint16_t *iport); +int istgt_listen(const char *ip, int port, int que); +int istgt_listen_unx(const char *lpath, int que); +int istgt_connect(const char *host, int port); +int istgt_connect_unx(const char *path); +int istgt_set_recvtimeout(int s, int msec); +int istgt_set_sendtimeout(int s, int msec); +int istgt_set_recvlowat(int s, int nbytes); +ssize_t istgt_read_socket(int s, void *buf, size_t nbytes, int timeout); +ssize_t istgt_write_socket(int s, const void *buf, size_t nbytes, int timeout); +ssize_t istgt_readline_socket(int sock, char *buf, size_t size, char *tmp, size_t tmpsize, int *tmpidx, int *tmpcnt, int timeout); +ssize_t istgt_writeline_socket(int sock, const char *buf, int timeout); + +#endif /* ISTGT_SOCK_H */ diff --git a/src/istgt_ver.h b/src/istgt_ver.h new file mode 100644 index 00000000..03d9e7a0 --- /dev/null +++ b/src/istgt_ver.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISTGT_VER_H +#define ISTGT_VER_H + +#define ISTGT_VERSION "0.5" +#define ISTGT_EXTRA_VERSION "20121028" + +#endif /* ISTGT_VER_H */ diff --git a/src/istgtcontrol.c b/src/istgtcontrol.c new file mode 100644 index 00000000..9b27d83c --- /dev/null +++ b/src/istgtcontrol.c @@ -0,0 +1,2319 @@ +/* + * Copyright (C) 2008-2012 Daisuke Aoyama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "build.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "istgt.h" +#include "istgt_ver.h" +#include "istgt_conf.h" +#include "istgt_sock.h" +#include "istgt_misc.h" +#include "istgt_md5.h" + +#if !defined(__GNUC__) +#undef __attribute__ +#define __attribute__(x) +#endif + +//#define TRACE_UCTL + +#define DEFAULT_UCTL_CONFIG BUILD_ETC_ISTGT "/istgtcontrol.conf" +#define DEFAULT_UCTL_TIMEOUT 60 +#define DEFAULT_UCTL_PORT 3261 +#define DEFAULT_UCTL_HOST "localhost" +#define DEFAULT_UCTL_LUN 0 +#define DEFAULT_UCTL_MTYPE "-" +#define DEFAULT_UCTL_MFLAGS "ro" +#define DEFAULT_UCTL_MSIZE "auto" + +#define MAX_LINEBUF 4096 +#define UCTL_CHAP_CHALLENGE_LEN 1024 + +typedef struct istgt_uctl_auth_t { + char *user; + char *secret; + char *muser; + char *msecret; + + uint8_t chap_id[1]; + uint8_t chap_mid[1]; + int chap_challenge_len; + uint8_t chap_challenge[UCTL_CHAP_CHALLENGE_LEN]; + int chap_mchallenge_len; + uint8_t chap_mchallenge[UCTL_CHAP_CHALLENGE_LEN]; +} UCTL_AUTH; + +typedef struct istgt_uctl_t { + CONFIG *config; + + char *host; + int port; + + int sock; + char *iqn; + int lun; + int OperationalMode; + int gottrace; + int traceflag; + int delayus; + int setzero; + char *mflags; + char *mfile; + char *msize; + char *mtype; + int persistopt; + + int family; + char caddr[MAX_ADDRBUF]; + char saddr[MAX_ADDRBUF]; + + UCTL_AUTH auth; + + int timeout; + int req_auth_auto; + int req_auth; + int req_auth_mutual; + + int recvtmpsize; + int recvtmpcnt; + int recvtmpidx; + int recvbufsize; + int sendbufsize; + int worksize; + char recvtmp[MAX_LINEBUF]; + char recvbuf[MAX_LINEBUF]; + char sendbuf[MAX_LINEBUF]; + char work[MAX_LINEBUF]; + char *cmd; + char *arg; + int setopt; + int setval; + char **setargv; + int setargcnt; + int detail; +} UCTL; +typedef UCTL *UCTL_Ptr; + + +static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2))); + +static void +fatal(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +typedef enum { + UCTL_CMD_OK = 0, + UCTL_CMD_ERR = 1, + UCTL_CMD_EOF = 2, + UCTL_CMD_QUIT = 3, + UCTL_CMD_DISCON = 4, + UCTL_CMD_REQAUTH = 5, + UCTL_CMD_CHAPSEQ = 6, +} UCTL_CMD_STATUS; + +//#define ARGS_DELIM " \t\r\n" +#define ARGS_DELIM " \t" + +static int +uctl_readline(UCTL_Ptr uctl) +{ + ssize_t total; + + total = istgt_readline_socket(uctl->sock, uctl->recvbuf, uctl->recvbufsize, + uctl->recvtmp, uctl->recvtmpsize, + &uctl->recvtmpidx, &uctl->recvtmpcnt, + uctl->timeout); + if (total < 0) { + return UCTL_CMD_DISCON; + } + if (total == 0) { + return UCTL_CMD_EOF; + } + return UCTL_CMD_OK; +} + +static int +uctl_writeline(UCTL_Ptr uctl) +{ + ssize_t total; + ssize_t expect; + + expect = strlen(uctl->sendbuf); + total = istgt_writeline_socket(uctl->sock, uctl->sendbuf, uctl->timeout); + if (total < 0) { + return UCTL_CMD_DISCON; + } + if (total != expect) { + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3))); + +static int +uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) +{ + va_list ap; + int rc; + + va_start(ap, format); + rc = vsnprintf(uctl->sendbuf, uctl->sendbufsize, format, ap); + va_end(ap); + return rc; +} + +static char * +get_banner(UCTL_Ptr uctl) +{ + char *banner; + int rc; + + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return NULL; + } + banner = xstrdup(trim_string(uctl->recvbuf)); + return banner; +} + +static int +is_err_req_auth(UCTL_Ptr uctl __attribute__((__unused__)), char *s) +{ + const char *req_auth_string = "auth required"; + +#ifdef TRACE_UCTL + printf("S=%s, Q=%s\n", s, req_auth_string); +#endif /* TRCAE_UCTL */ + if (strncasecmp(s, req_auth_string, strlen(req_auth_string)) == 0) + return 1; + return 0; +} + +static int +is_err_chap_seq(UCTL_Ptr uctl __attribute__((__unused__)), char *s) +{ + const char *chap_seq_string = "CHAP sequence error"; + +#ifdef TRACE_UCTL + printf("S=%s, Q=%s\n", s, chap_seq_string); +#endif /* TRCAE_UCTL */ + if (strncasecmp(s, chap_seq_string, strlen(chap_seq_string)) == 0) + return 1; + return 0; +} + +static int +exec_quit(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + uctl_snprintf(uctl, "QUIT\n"); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_noop(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + uctl_snprintf(uctl, "NOOP\n"); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_version(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + char *version; + char *extver; + int rc; + + /* send command */ + uctl_snprintf(uctl, "VERSION\n"); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) { + break; + } + version = strsepq(&arg, delim); + extver = strsepq(&arg, delim); + printf("target version %s %s\n", version, extver); + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_unload(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "UNLOAD \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_load(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "LOAD \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_list(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + char *target; + char *num; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "LIST \"%s\"\n", uctl->iqn); + } else { + uctl_snprintf(uctl, "LIST\n"); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + target = strsepq(&arg, delim); + num = strsepq(&arg, delim); + printf("%s %s\n", target, num); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_change(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->mfile == NULL || uctl->mtype == NULL + || uctl->mflags == NULL || uctl->msize == NULL) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "CHANGE \"%s\" %d \"%s\" " + "\"%s\" \"%s\" \"%s\"\n", + uctl->iqn, uctl->lun, uctl->mtype, + uctl->mflags, uctl->mfile, uctl->msize); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_reset(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "RESET \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_clear(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "CLEAR \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} +static int +exec_refresh(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + uctl_snprintf(uctl, "REFRESH \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "%s: %s\n", result, arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_sync(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "SYNC \"%s\" %d\n" + ,uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_persist(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "PERSIST \"%s\" %d %d\n" + ,uctl->iqn, uctl->lun, uctl->persistopt); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_start(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "START \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_stop(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn == NULL || uctl->lun < 0) { + return UCTL_CMD_ERR; + } + uctl_snprintf(uctl, "STOP \"%s\" %d\n", + uctl->iqn, uctl->lun); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_mem(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* Send Command */ + uctl_snprintf(uctl, "%s\n", "MEM"); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_log(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* Send Command */ + printf("LOG %d %d %d\n", uctl->gottrace, uctl->traceflag, uctl->delayus); + uctl_snprintf(uctl, "LOG %d %d %d\n", uctl->gottrace, uctl->traceflag, uctl->delayus); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} +static int +exec_memdebug(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* Send Command */ + uctl_snprintf(uctl, "%s\n", "MEMDEBUG"); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_modify(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->OperationalMode < 0) { + return UCTL_CMD_ERR; + } + + /* Send Command */ + uctl_snprintf(uctl, "MODIFY %d\n", + uctl->OperationalMode); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + + + + +static int +exec_status(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "STATUS \"%s\"\n", uctl->iqn); + }else { + uctl_snprintf(uctl, "STATUS\n"); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + printf("%s\n", arg); + } + + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_info(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "INFO \"%s\"\n", uctl->iqn); + } else { + uctl_snprintf(uctl, "INFO\n"); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} +static int +exec_dump(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + char *type; + char *var; + char *c_num; + char *isid; + char *tsih; + char *cid; + char *t_ip; + char *i_ip; + char *i_name; + int flag = 0; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "DUMP %d \"%s\"\n", uctl->detail, uctl->iqn); + } else { + uctl_snprintf(uctl, "DUMP %d\n", uctl->detail); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + type = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (strcmp(type, "LUN") == 0) { + printf("--------------------\n"); + while((var = strsepq(&arg, delim)) != NULL) + printf("%s\n", var); + flag = 1; + continue; + } + else if(strcmp(type, "CONN") == 0) { + if(flag == 1) { + printf("c# ISID TSIH CID T_IP I_IP NAME\n"); + flag = 0; + } + c_num = strsepq(&arg, delim); + isid = strsepq(&arg, delim); + tsih = strsepq(&arg, delim); + cid = strsepq(&arg, delim); + t_ip = strsepq(&arg, delim); + i_ip = strsepq(&arg, delim); + i_name = strsepq(&arg, delim); + printf("%-6s %-16s %-4s %3s %3s %-15s %s\n", c_num, isid, tsih, cid, t_ip, i_ip, i_name); + } + else if(strcmp(type, "TOTAL") == 0) { + printf("--------------------\n"); + if(uctl->iqn != NULL) + continue; + printf("TOTAL:\n"); + while((var = strsepq(&arg, delim)) != NULL) + printf("%s\n", var); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_stats(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + /*if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "STATS IQN \"%s\"\n", uctl->iqn); + } else if (uctl->lun != -1) { + uctl_snprintf(uctl, "STATS LU \"%d\"\n", uctl->lun); + } else { + uctl_snprintf(uctl, "STATS ALL \n"); + }*/ + uctl_snprintf(uctl, "STATS %d\n", uctl->setzero); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_maxtime(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + if(uctl->iqn == NULL) + uctl_snprintf(uctl, "MAXTIME ALL %d\n", uctl->setzero); + else + uctl_snprintf(uctl, "MAXTIME \"%s\" %d\n", uctl->iqn, uctl->setzero); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_set(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc = 0, i; + + if(uctl->setopt != 15) + { + if(uctl->iqn == NULL) + uctl_snprintf(uctl, "SET ALL %d %d %d\n", uctl->lun, uctl->setopt, uctl->setval); + else + uctl_snprintf(uctl, "SET \"%s\" %d %d %d\n",uctl->iqn, uctl->lun, uctl->setopt, uctl->setval); + } + else + { + if(uctl->iqn == NULL) + rc = snprintf(uctl->sendbuf, uctl->sendbufsize, "SET ALL %d %d %d", uctl->lun, uctl->setopt, uctl->setargcnt-1); + else + rc = snprintf(uctl->sendbuf, uctl->sendbufsize, "SET \"%s\" %d %d %d", uctl->iqn, uctl->lun, uctl->setopt, uctl->setargcnt-1); + + if(rc >= uctl->sendbufsize) + return UCTL_CMD_ERR; + + for(i=1;isetargcnt;i++) + { + rc += snprintf(uctl->sendbuf+rc, uctl->sendbufsize-rc, " %s", uctl->setargv[i]); + if(rc >= uctl->sendbufsize) + return UCTL_CMD_ERR; + } + rc += snprintf(uctl->sendbuf+rc, uctl->sendbufsize-rc, "\n"); + if(rc >= uctl->sendbufsize) + return UCTL_CMD_ERR; + } + + printf("cmd: %s\n", uctl->sendbuf); + + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} +static int +exec_rsv(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "RSV \"%s\"\n", uctl->iqn); + } else { + uctl_snprintf(uctl, "RSV \n"); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static int +exec_que(UCTL_Ptr uctl) +{ + const char *delim = ARGS_DELIM; + char *arg; + char *result; + int rc; + + /* send command */ + if (uctl->iqn != NULL) { + uctl_snprintf(uctl, "QUE IQN \"%s\"\n", uctl->iqn); + } else if (uctl->lun != -1) { + uctl_snprintf(uctl, "QUE LU \"%d\"\n", uctl->lun); + } else { + uctl_snprintf(uctl, "QUE ALL \n"); + } + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive result */ + while (1) { + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, uctl->cmd) != 0) + break; + if (uctl->iqn != NULL) { + printf("%s\n", arg); + } else { + printf("%s\n", arg); + } + } + if (strcmp(result, "OK") != 0) { + if (is_err_req_auth(uctl, arg)) + return UCTL_CMD_REQAUTH; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} +typedef struct exec_table_t +{ + const char *name; + int (*func) (UCTL_Ptr uctl); + int req_argc; + int req_target; +} EXEC_TABLE; + +static EXEC_TABLE exec_table[] = +{ + { "QUIT", exec_quit, 0, 0 }, + { "NOOP", exec_noop, 0, 0 }, + { "VERSION", exec_version, 0, 0 }, + { "LIST", exec_list, 0, 0 }, + { "UNLOAD", exec_unload, 0, 1 }, + { "LOAD", exec_load, 0, 1 }, + { "CHANGE", exec_change, 1, 1 }, + { "RESET", exec_reset, 0, 1 }, + { "CLEAR", exec_clear, 0, 1 }, + { "SYNC", exec_sync, 0, 1 }, + { "PERSIST", exec_persist, 1, 1}, + { "REFRESH", exec_refresh, 0, 0 }, + { "START", exec_start, 0, 1 }, + { "STOP", exec_stop, 0, 1 }, + {"MODIFY", exec_modify, 0, 0 }, + { "STATUS", exec_status, 0, 0}, + { "INFO", exec_info, 0, 0 }, + { "DUMP", exec_dump, 0, 0 }, + {"MEM", exec_mem, 0, 0 }, + {"MEMDEBUG", exec_memdebug, 0, 0 }, + {"LOG", exec_log, 0, 0 }, + {"RSV", exec_rsv, 0, 0 }, + {"QUE", exec_que, 0, 0 }, + {"STATS", exec_stats, 0, 0 }, + {"SET", exec_set, 0, 1}, + {"MAXTIME", exec_maxtime, 0, 0}, + { NULL, NULL, 0, 0 }, +}; + +static int +do_auth(UCTL_Ptr uctl) +{ + uint8_t uctlmd5[ISTGT_MD5DIGEST_LEN]; + uint8_t resmd5[ISTGT_MD5DIGEST_LEN]; + ISTGT_MD5CTX md5ctx; + const char *delim = ARGS_DELIM; + char *arg; + char *result; + char *label; + char *chap_i; + char *chap_c; + char *chap_n; + char *chap_r; + char *hexmd5; + char *hexchallenge; + char *workp; + int worksize; + int algorithm = 5; /* CHAP with MD5 */ + int rc; + +#ifdef TRACE_UCTL + printf("do_auth: user=%s, secret=%s, muser=%s, msecret=%s\n", + uctl->auth.user, + uctl->auth.secret, + uctl->auth.muser, + uctl->auth.msecret); +#endif /* TRACE_UCTL */ + + /* send algorithm CHAP_A */ + uctl_snprintf(uctl, "AUTH CHAP_A %d\n", + algorithm); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive CHAP_IC */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "AUTH") != 0) { + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + + label = strsepq(&arg, delim); + chap_i = strsepq(&arg, delim); + chap_c = strsepq(&arg, delim); + if (label == NULL || chap_i == NULL || chap_c == NULL) { + fprintf(stderr, "CHAP sequence error\n"); + return UCTL_CMD_ERR; + } + if (strcasecmp(label, "CHAP_IC") != 0) { + fprintf(stderr, "CHAP sequence error\n"); + return UCTL_CMD_ERR; + } + + /* Identifier */ + uctl->auth.chap_id[0] = (uint8_t) strtol(chap_i, NULL, 10); + /* Challenge Value */ + rc = istgt_hex2bin(uctl->auth.chap_challenge, + UCTL_CHAP_CHALLENGE_LEN, + chap_c); + if (rc < 0) { + fprintf(stderr, "challenge format error\n"); + return UCTL_CMD_ERR; + } + uctl->auth.chap_challenge_len = rc; + + if (uctl->auth.user == NULL || uctl->auth.secret == NULL) { + fprintf(stderr, "ERROR auth user or secret is missing\n"); + return UCTL_CMD_ERR; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, uctl->auth.chap_id, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, uctl->auth.secret, + strlen(uctl->auth.secret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, uctl->auth.chap_challenge, + uctl->auth.chap_challenge_len); + /* uctlmd5 is Response Value */ + istgt_md5final(uctlmd5, &md5ctx); + + workp = uctl->work; + worksize = uctl->worksize; + + istgt_bin2hex(workp, worksize, + uctlmd5, ISTGT_MD5DIGEST_LEN); + hexmd5 = workp; + worksize -= strlen(hexmd5) + 1; + workp += strlen(hexmd5) + 1; + + /* mutual CHAP? */ + if (uctl->req_auth_mutual) { + /* Identifier is one octet */ + istgt_gen_random(uctl->auth.chap_mid, 1); + /* Challenge Value is a variable stream of octets */ + /* (binary length MUST not exceed 1024 bytes) */ + uctl->auth.chap_mchallenge_len = UCTL_CHAP_CHALLENGE_LEN; + istgt_gen_random(uctl->auth.chap_mchallenge, + uctl->auth.chap_mchallenge_len); + + istgt_bin2hex(workp, worksize, + uctl->auth.chap_mchallenge, + uctl->auth.chap_mchallenge_len); + hexchallenge = workp; + worksize -= strlen(hexchallenge) + 1; + workp += strlen(hexchallenge) + 1; + + /* send CHAP_NR with CHAP_IC */ + uctl_snprintf(uctl, "AUTH CHAP_NR %s %s %d %s\n", + uctl->auth.user, hexmd5, + (int) uctl->auth.chap_mid[0], hexchallenge); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + + /* receive CHAP_NR */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "AUTH") != 0) { + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + + label = strsepq(&arg, delim); + chap_n = strsepq(&arg, delim); + chap_r = strsepq(&arg, delim); + if (label == NULL || chap_n == NULL || chap_r == NULL) { + fprintf(stderr, "CHAP sequence error\n"); + return UCTL_CMD_ERR; + } + if (strcasecmp(label, "CHAP_NR") != 0) { + fprintf(stderr, "CHAP sequence error\n"); + return UCTL_CMD_ERR; + } + + rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, chap_r); + if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) { + fprintf(stderr, "response format error\n"); + return UCTL_CMD_ERR; + } + + if (uctl->auth.muser == NULL || uctl->auth.msecret == NULL) { + fprintf(stderr, "ERROR auth user or secret is missing\n"); + return UCTL_CMD_ERR; + } + + istgt_md5init(&md5ctx); + /* Identifier */ + istgt_md5update(&md5ctx, uctl->auth.chap_mid, 1); + /* followed by secret */ + istgt_md5update(&md5ctx, uctl->auth.msecret, + strlen(uctl->auth.msecret)); + /* followed by Challenge Value */ + istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge, + uctl->auth.chap_mchallenge_len); + /* uctlmd5 is expecting Response Value */ + istgt_md5final(uctlmd5, &md5ctx); + + /* compare MD5 digest */ + if (memcmp(uctlmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) { + /* not match */ + fprintf(stderr, "ERROR auth user or secret is missing\n"); + /* discard result line */ + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + /* final with ERR */ + return UCTL_CMD_ERR; + } + } else { + /* not mutual */ + /* send CHAP_NR */ + uctl_snprintf(uctl, "AUTH CHAP_NR %s %s\n", + uctl->auth.user, hexmd5); + rc = uctl_writeline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + } + + /* receive result */ + rc = uctl_readline(uctl); + if (rc != UCTL_CMD_OK) { + return rc; + } + arg = trim_string(uctl->recvbuf); + result = strsepq(&arg, delim); + strupr(result); + if (strcmp(result, "OK") != 0) { + if (is_err_chap_seq(uctl, arg)) + return UCTL_CMD_CHAPSEQ; + fprintf(stderr, "ERROR %s\n", arg); + return UCTL_CMD_ERR; + } + return UCTL_CMD_OK; +} + +static char * +uctl_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2) +{ + CF_ITEM *ip; + CF_VALUE *vp; + int i; + + ip = istgt_find_cf_nitem(sp, key, idx1); + if (ip == NULL) + return NULL; + vp = ip->val; + if (vp == NULL) + return NULL; + for (i = 0; vp != NULL; vp = vp->next) { + if (i == idx2) + return vp->value; + i++; + } + return NULL; +} + +static char * +uctl_get_nval(CF_SECTION *sp, const char *key, int idx) +{ + CF_ITEM *ip; + CF_VALUE *vp; + + ip = istgt_find_cf_nitem(sp, key, idx); + if (ip == NULL) + return NULL; + vp = ip->val; + if (vp == NULL) + return NULL; + return vp->value; +} + +static char * +uctl_get_val(CF_SECTION *sp, const char *key) +{ + return uctl_get_nval(sp, key, 0); +} + +static int +uctl_get_nintval(CF_SECTION *sp, const char *key, int idx) +{ + const char *v; + int value; + + v = uctl_get_nval(sp, key, idx); + if (v == NULL) + return -1; + value = (int)strtol(v, NULL, 10); + return value; +} + +static int +uctl_get_intval(CF_SECTION *sp, const char *key) +{ + return uctl_get_nintval(sp, key, 0); +} + +static int +uctl_init(UCTL_Ptr uctl) +{ + CF_SECTION *sp; + const char *val; + const char *user, *muser; + const char *secret, *msecret; + int timeout; + int port; + int lun; + int i; + + sp = istgt_find_cf_section(uctl->config, "Global"); + if (sp == NULL) { + fprintf(stderr, "find_cf_section failed()\n"); + return -1; + } + + val = uctl_get_val(sp, "Comment"); + if (val != NULL) { + /* nothing */ +#ifdef TRACE_UCTL + printf("Comment %s\n", val); +#endif /* TRACE_UCTL */ + } + + val = uctl_get_val(sp, "Host"); + if (val == NULL) { + val = DEFAULT_UCTL_HOST; + } + uctl->host = xstrdup(val); +#ifdef TRACE_UCTL + printf("Host %s\n", uctl->host); +#endif /* TRACE_UCTL */ + + port = uctl_get_intval(sp, "Port"); + if (port < 0) { + port = DEFAULT_UCTL_PORT; + } + uctl->port = port; +#ifdef TRACE_UCTL + printf("Port %d\n", uctl->port); +#endif /* TRACE_UCTL */ + + val = uctl_get_val(sp, "TargetName"); + if (val == NULL) { + val = NULL; + } + uctl->iqn = xstrdup(val); +#ifdef TRACE_UCTL + printf("TargetName %s\n", uctl->iqn); +#endif /* TRACE_UCTL */ + + lun = uctl_get_intval(sp, "Lun"); + if (lun < 0) { + lun = DEFAULT_UCTL_LUN; + } + uctl->lun = lun; +#ifdef TRACE_UCTL + printf("Lun %d\n", uctl->lun); +#endif /* TRACE_UCTL */ + + val = uctl_get_val(sp, "Flags"); + if (val == NULL) { + val = DEFAULT_UCTL_MFLAGS; + } + uctl->mflags = xstrdup(val); +#ifdef TRACE_UCTL + printf("Flags %s\n", uctl->mflags); +#endif /* TRACE_UCTL */ + + val = uctl_get_val(sp, "Size"); + if (val == NULL) { + val = DEFAULT_UCTL_MSIZE; + } + uctl->msize = xstrdup(val); +#ifdef TRACE_UCTL + printf("Size %s\n", uctl->msize); +#endif /* TRACE_UCTL */ + + timeout = uctl_get_intval(sp, "Timeout"); + if (timeout < 0) { + timeout = DEFAULT_UCTL_TIMEOUT; + } + uctl->timeout = timeout; +#ifdef TRACE_UCTL + printf("Timeout %d\n", uctl->timeout); +#endif /* TRACE_UCTL */ + + val = uctl_get_val(sp, "AuthMethod"); + if (val == NULL) { + uctl->req_auth_auto = 0; + uctl->req_auth = 0; + } else { + uctl->req_auth_auto = 0; + for (i = 0; ; i++) { + val = uctl_get_nmval(sp, "AuthMethod", 0, i); + if (val == NULL) + break; + if (strcasecmp(val, "CHAP") == 0) { + uctl->req_auth = 1; + } else if (strcasecmp(val, "Mutual") == 0) { + uctl->req_auth_mutual = 1; + } else if (strcasecmp(val, "Auto") == 0) { + uctl->req_auth_auto = 1; + uctl->req_auth = 0; + uctl->req_auth_mutual = 0; + } else if (strcasecmp(val, "None") == 0) { + uctl->req_auth = 0; + uctl->req_auth_mutual = 0; + } else { + fprintf(stderr, "unknown auth\n"); + return -1; + } + } + if (uctl->req_auth_mutual && !uctl->req_auth) { + fprintf(stderr, "Mutual but not CHAP\n"); + return -1; + } + } +#ifdef TRACE_UCTL + if (uctl->req_auth == 0) { + printf("AuthMethod Auto\n"); + } else { + printf("AuthMethod %s %s\n", + uctl->req_auth ? "CHAP" : "", + uctl->req_auth_mutual ? "Mutual" : ""); + } +#endif /* TRACE_UCTL */ + + val = uctl_get_nval(sp, "Auth", 0); + if (val == NULL) { + user = secret = muser = msecret = NULL; + } else { + user = uctl_get_nmval(sp, "Auth", 0, 0); + secret = uctl_get_nmval(sp, "Auth", 0, 1); + muser = uctl_get_nmval(sp, "Auth", 0, 2); + msecret = uctl_get_nmval(sp, "Auth", 0, 3); + } + uctl->auth.user = xstrdup(user); + uctl->auth.secret = xstrdup(secret); + uctl->auth.muser = xstrdup(muser); + uctl->auth.msecret = xstrdup(msecret); +#ifdef TRACE_UCTL + printf("user=%s, secret=%s, muser=%s, msecret=%s\n", + user, secret, muser, msecret); +#endif /* TRACE_UCTL */ + + return 0; +} + +static void +usage(void) +{ + printf("istgtcotrol [options] []\n"); + printf("options:\n"); + printf("default may be changed by configuration file\n"); + printf(" -c config config file (default %s)\n", DEFAULT_UCTL_CONFIG); + printf(" -h host target host name or IP (default %s)\n", DEFAULT_UCTL_HOST); + printf(" -p port port number (default %d)\n", DEFAULT_UCTL_PORT); + printf(" -t target target iqn\n"); + printf(" -l lun target lun (default %d)\n", DEFAULT_UCTL_LUN); + printf(" -f flags media flags (default %s)\n", DEFAULT_UCTL_MFLAGS); + printf(" -s size media size (default %s)\n", DEFAULT_UCTL_MSIZE); + printf(" -q quiet mode\n"); + printf(" -v verbose mode\n"); + printf(" -A method authentication method (CHAP/Mutual CHAP/Auto)\n"); + printf(" -U user auth user\n"); + printf(" -S secret auth secret\n"); + printf(" -M muser mutual auth user\n"); + printf(" -R msecret mutual auth secret\n"); + printf(" -H show this usage\n"); + printf(" -V show version\n"); + printf(" -F Fake Operational Mode\n"); + printf(" -N Normal Operational Mode\n"); + printf("command:\n"); + printf(" noop no operation\n"); + printf(" version show target version\n"); + printf(" list list all or specified target\n"); + printf(" load load media to specified unit\n"); + printf(" unload unload media from specified unit\n"); + printf(" change change media with at specified unit\n"); + printf(" sync sync persistent reservation to zap\n"); + printf(" persist turn persist or \n"); + printf(" reset reset specified lun of target\n"); + printf(" clear clear the persistent reservation of a specified lun\n"); + printf(" refresh refresh to reload the lun configuration\n"); + printf(" start open the lun device\n"); + printf(" stop close the lun device\n"); + printf(" modify Modify all the lun devices to Fake/Normal\n"); + printf(" status get the status of all or specified lun device \n"); + printf(" info show connections of target\n"); + printf(" maxtime list the IOs which took maximum time to process\n"); + printf(" set set values for variables:\n"); + printf(" Syntax: istgtcontrol -t set \n"); + printf(" Variables :\n"); + printf(" 1\tsend_abrt_resp(Yes->1 No->0)\n"); + printf(" 2\tabort_result_queue(Yes->1 No->0)\n"); + printf(" 3\ttwait_inflights(Yes->1 No->0)\n"); + printf(" 4\tmax_unmap_sectors\n"); + printf(" 5\tclear_resv(Yes->1 No->0)\n"); + printf(" 6\tATS(Disable->0 Enable->1)\n"); + printf(" 7\tXCOPY(Disable->0 Enable->1)\n"); + printf(" 11\tabort_release(Yes->1 No->0)\n"); +} + +int +main(int argc, char *argv[]) +{ + const char *config_file = DEFAULT_UCTL_CONFIG; + CONFIG *config; + UCTL xuctl, *uctl; + struct sigaction sigact, sigoldact; + int (*func) (UCTL_Ptr); + int port = -1; + int lun = -1; + const char *host = NULL; + const char *mflags = NULL; + const char *mfile = NULL; + const char *persistopt = NULL; + const char *msize = NULL; + const char *mtype = DEFAULT_UCTL_MTYPE; + char *target = NULL; + char *user = NULL; + char *secret = NULL; + char *muser = NULL; + char *msecret = NULL; + char *cmd = NULL; + char *banner; + long l; + int detail = 0; + int OperationalMode = -1; + int traceflag = ISTGT_TRACE_NONE; + int gottrace = 0; + int delayus = -2; + int setzero = 0; + int exec_result; + int req_argc; + int req_target; + int quiet = 0; + int verbose = 0; + int req_auth = -1; + int ch; + int sock; + int rc; + int i; + +#ifdef HAVE_SETPROCTITLE + setproctitle("version %s (%s)", + ISTGT_VERSION, ISTGT_EXTRA_VERSION); +#endif + + memset(&xuctl, 0, sizeof xuctl); + uctl = &xuctl; + + while ((ch = getopt(argc, argv, "c:h:p:t:l:f:s:qvaA:U:S:M:R:T:L:zFHNV")) != -1) { + switch (ch) { + case 'c': + config_file = optarg; + break; + case 'h': + host = optarg; + break; + case 'p': + l = strtol(optarg, NULL, 10); + if (l < 0 || l > 65535) { + fatal("invalid port %s\n", optarg); + } + port = (int) l; + break; + case 't': + target = optarg; + break; + case 'l': + l = strtol(optarg, NULL, 10); + if (l < 0 || l > 0x3fff) { + fatal("invalid lun %s\n", optarg); + } + lun = (int) l; + break; + case 'f': + mflags = optarg; + break; + case 's': + msize = optarg; + break; + case 'q': + quiet = 1; + break; + case 'v': + verbose = 1; + break; + case 'a': + detail = 1; + break; + case 'A': + if (strcasecmp(optarg, "CHAP") == 0) { + req_auth = 1; + } else if (strcasecmp(optarg, "Mutual") == 0 + || strcasecmp(optarg, "Mutual CHAP") == 0 + || strcasecmp(optarg, "CHAP Mutual") == 0) { + req_auth = 2; + } else if (strcasecmp(optarg, "Auto") == 0) { + req_auth = 0; + } else { + usage(); + exit(EXIT_SUCCESS); + } + break; + case 'U': + user = optarg; + break; + case 'S': + secret = optarg; +#ifndef HAVE_SETPROCTITLE + secret = xstrdup(optarg); + memset(optarg, 'x', strlen(optarg)); +#endif + break; + case 'M': + muser = optarg; + break; + case 'R': + msecret = optarg; +#ifndef HAVE_SETPROCTITLE + msecret = xstrdup(optarg); + memset(optarg, 'x', strlen(optarg)); +#endif + break; + case 'F': + OperationalMode = 1; + break; + case 'N': + OperationalMode = 0; + break; + case 'T': + gottrace = 1; + if (strcasecmp(optarg, "NET") == 0) { + traceflag |= ISTGT_TRACE_NET; + } else if (strcasecmp(optarg, "ISCSI") == 0) { + traceflag |= ISTGT_TRACE_ISCSI; + } else if (strcasecmp(optarg, "SCSI") == 0) { + traceflag |= ISTGT_TRACE_SCSI; + } else if (strcasecmp(optarg, "LU") == 0) { + traceflag |= ISTGT_TRACE_LU; + } else if (strcasecmp(optarg, "PQ") == 0) { + traceflag |= ISTGT_TRACE_PQ; + } else if (strcasecmp(optarg, "ALL") == 0) { + traceflag |= ISTGT_TRACE_ALL; + } else if (strcasecmp(optarg, "MEM") == 0) { + traceflag |= ISTGT_TRACE_MEM; + } else if (strcasecmp(optarg, "PROF") == 0) { + traceflag |= ISTGT_TRACE_PROF; + } else if (strcasecmp(optarg, "PROFX") == 0) { + traceflag |= ISTGT_TRACE_PROFX; + } else if (strcasecmp(optarg, "CMD") == 0) { + traceflag |= ISTGT_TRACE_CMD; + } else if (strcasecmp(optarg, "NONE") == 0) { + traceflag = ISTGT_TRACE_NONE; + } else { + gottrace = 0; + } + break; + case 'L': + l = strtol(optarg, NULL, 10); + if (l > 999000) + l = 999000; + else if (l < -1) + l = -2; + delayus = (int) l; + break; + case 'z': + setzero = 1; + break; + case 'V': + printf("istgtcontrol version %s (%s)\n", + ISTGT_VERSION, ISTGT_EXTRA_VERSION); + exit(EXIT_SUCCESS); + case 'H': + default: + usage(); + exit(EXIT_SUCCESS); + } + } + argc -= optind; + argv += optind; + + /* read config files */ + config = istgt_allocate_config(); + rc = istgt_read_config(config, config_file); + if (rc < 0) { + fprintf(stderr, "config error\n"); + exit(EXIT_FAILURE); + } + if (config->section == NULL) { + fprintf(stderr, "empty config\n"); + istgt_free_config(config); + exit(EXIT_FAILURE); + } + uctl->config = config; + //istgt_print_config(config); + + istgtcontrol_open_log(); + + /* take specified command */ + if (argc < 1) { + error_usage_return: + istgt_free_config(config); + usage(); + exit(EXIT_FAILURE); + } + cmd = strupr(xstrdup(argv[0])); + argc--; + argv++; + + /* get function pointer and parameters for specified command */ + func = NULL; + req_argc = -1; + req_target = -1; + for (i = 0; exec_table[i].name != NULL; i++) { + if (cmd[0] == exec_table[i].name[0] + && strcmp(cmd, exec_table[i].name) == 0) { + func = exec_table[i].func; + req_argc = exec_table[i].req_argc; + req_target = exec_table[i].req_target; + break; + } + } + if (func == NULL) { + istgt_free_config(config); + fatal("unknown command %s\n", cmd); + } + + /* patrameter check */ + if (argc < req_argc) { + goto error_usage_return; + } +#if 0 + if (req_target) { + if (target == NULL) { + goto error_usage_return; + } + } +#endif + + /* take args */ + if (strcmp(cmd, "CHANGE") == 0) { + /* change require file */ + mfile = argv[0]; + } + + if (strcmp(cmd, "PERSIST") == 0) { + /* persist requires option 0 or 1 */ + persistopt = argv[0]; + } + if (strcmp(cmd, "SET") == 0) { + uctl->setopt = atoi(argv[0]); + uctl->setval = atoi(argv[1]); + uctl->setargv = argv; + uctl->setargcnt = argc; + } + + + /* build parameters */ + rc = uctl_init(uctl); + if (rc < 0) { + fprintf(stderr, "uctl_init() failed\n"); + istgt_free_config(config); + exit(EXIT_FAILURE); + } + uctl->recvtmpcnt = 0; + uctl->recvtmpidx = 0; + uctl->recvtmpsize = sizeof uctl->recvtmp; + uctl->recvbufsize = sizeof uctl->recvbuf; + uctl->sendbufsize = sizeof uctl->sendbuf; + uctl->worksize = sizeof uctl->work; + uctl->detail = detail; + + /* override by command line */ + if (user != NULL) { + xfree(uctl->auth.user); + uctl->auth.user = xstrdup(user); + } + if (secret != NULL) { + xfree(uctl->auth.secret); + uctl->auth.secret = xstrdup(secret); + } + if (muser != NULL) { + xfree(uctl->auth.muser); + uctl->auth.muser = xstrdup(muser); + } + if (msecret != NULL) { + xfree(uctl->auth.msecret); + uctl->auth.msecret = xstrdup(msecret); + } + if (req_target) { + if (uctl->iqn == NULL + && target == NULL) { + goto error_usage_return; + } + } + if (req_auth >= 0) { + uctl->req_auth_auto = 1; + uctl->req_auth = 0; + uctl->req_auth_mutual = 0; + if (req_auth > 1) { + uctl->req_auth_auto = 0; + uctl->req_auth = 1; + uctl->req_auth_mutual = 1; + } else if (req_auth > 0) { + uctl->req_auth_auto = 0; + uctl->req_auth = 1; + } + } +#ifdef TRACE_UCTL + printf("auto=%d, auth=%d, mutual=%d\n", + uctl->req_auth_auto, uctl->req_auth, uctl->req_auth_mutual); +#endif /* TRACE_UCTL */ + + if (host != NULL) { + xfree(uctl->host); + uctl->host = xstrdup(host); + } + if (port >= 0) { + uctl->port = port; + } + if (target != NULL) { + xfree(uctl->iqn); + if (strcasecmp(target, "ALL") == 0) { + uctl->iqn = NULL; + } else { + uctl->iqn = escape_string(target); + } + } + if (lun >= 0) { + uctl->lun = lun; + } + + if (OperationalMode < 0) { + uctl->OperationalMode = DEFAULT_OPERATIONAL_MODE; + }else { + uctl->OperationalMode = OperationalMode; + } + uctl->gottrace = gottrace; + uctl->traceflag = traceflag; + uctl->delayus = delayus; + uctl->setzero = setzero; + if (mflags != NULL) { + xfree(uctl->mflags); + uctl->mflags = escape_string(mflags); + } + uctl->mfile = escape_string(mfile); + if (msize != NULL) { + xfree(uctl->msize); + uctl->msize = escape_string(msize); + } + uctl->mtype = escape_string(mtype); + uctl->cmd = escape_string(cmd); + if(persistopt != NULL) + uctl->persistopt = (persistopt[0] == '1' ? 1 : 0); + + /* show setting */ +#define NULLP(S) ((S) == NULL ? "NULL" : (S)) + if (verbose) { + printf("iqn=%s, lun=%d\n", NULLP(uctl->iqn), uctl->lun); + printf("media file=%s, flags=%s, size=%s\n", + NULLP(uctl->mfile), NULLP(uctl->mflags), NULLP(uctl->msize)); + } + + /* set signals */ + memset(&sigact, 0, sizeof sigact); + memset(&sigoldact, 0, sizeof sigoldact); + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + if (sigaction(SIGPIPE, &sigact, &sigoldact) != 0) { + istgt_free_config(config); + fatal("sigaction() failed"); + } + + /* connect to target */ + if (verbose) { + printf("connect to %s else to %s:%d\n", ISTGT_UCTL_UNXPATH, uctl->host, uctl->port); + } + sock = istgt_connect_unx(ISTGT_UCTL_UNXPATH); + if (sock < 0) { + printf("istgt_connect(%s) failed\n", ISTGT_UCTL_UNXPATH); + sock = istgt_connect(uctl->host, uctl->port); + } + if (sock < 0) { + istgt_free_config(config); + fatal("istgt_connect(%s:%d) failed\n", uctl->host, uctl->port); + } + uctl->sock = sock; + + /* get target banner (ready to send) */ + banner = get_banner(uctl); + if (banner == NULL) { + close(uctl->sock); + istgt_free_config(config); + fatal("get_banner() failed\n"); + } + if (verbose) { + printf("target banner \"%s\"\n", banner); + } + + /* authentication */ + retry_auth: + if (uctl->req_auth) { + rc = do_auth(uctl); + if (rc != UCTL_CMD_OK) { + if (rc == UCTL_CMD_REQAUTH + || rc == UCTL_CMD_CHAPSEQ) { + retry_auth_auto: + /* Auth negotiation */ + if (uctl->req_auth == 0) { +#ifdef TRCAE_UCTL + printf("Auto negotiation CHAP\n"); +#endif /* TRCAE_UCTL */ + uctl->req_auth = 1; + goto retry_auth; + } else if (uctl->req_auth_mutual == 0) { +#ifdef TRCAE_UCTL + printf("Auto negotiation Mutual CHAP\n"); +#endif /* TRCAE_UCTL */ + uctl->req_auth_mutual = 1; + goto retry_auth; + } + } + if (!quiet) { + printf("AUTH failed\n"); + } + exec_result = rc; + goto disconnect; + } + } + + /* send specified command */ + rc = func(uctl); + exec_result = rc; + if (rc != UCTL_CMD_OK) { + if (rc == UCTL_CMD_REQAUTH + || rc == UCTL_CMD_CHAPSEQ) { + goto retry_auth_auto; + } + if (!quiet) { + printf("ABORT %s command\n", uctl->cmd); + } + } else { + if (!quiet) { + printf("DONE %s command\n", uctl->cmd); + } + } + + /* disconnect from target */ + disconnect: + rc = exec_quit(uctl); + if (rc != UCTL_CMD_OK) { + fprintf(stderr, "QUIT failed\n"); + /* error but continue */ + } + + /* cleanup */ + close(sock); + xfree(uctl->host); + xfree(uctl->iqn); + xfree(uctl->mflags); + xfree(uctl->mfile); + xfree(uctl->msize); + xfree(uctl->mtype); + xfree(uctl->cmd); + xfree(banner); + xfree(cmd); + istgt_free_config(config); + istgtcontrol_close_log(); + + /* return value as execution result */ + if (exec_result != UCTL_CMD_OK) { + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/src/stamp-depend b/src/stamp-depend new file mode 100644 index 00000000..e69de29b