高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先



DV 29 - vRefNum から取得する SCSI ID

(更新日: 97 年 5 月 23 日)

Q: 特定のファイルを含むディスクボリュームの SCSI IDを取得したいのですが、どんな方法があるでしょうか。

A: ここでは、対象となるドライブが SCSI でない (フロッピー、IDE、RAM ディスクなど) 場合も見越して説明を行います。


SCSI Manager 4.3 がインストールされているかどうかで、この質問には 2 つの回答が考えられます。SCSI Manager 4.3 がインストールされていない場合は、SCSI デバイスがユニットテーブル内の特定の場所に位置するという事実にもとづいて対処します。『Inside Macintosh:Devices』を要約すると、SCSI ドライバはユニットテーブルのスロット 32-40 に順に入ります。このため、SCSI 0 に対するドライバはスロット 32、SCSI 1 に対するドライバはスロット 33、... にあります。

slot number = -(refnum-1)

上の式により、SCSI 0 に対するドライバは refnum -33、SCSI 1 に対するドライバ refnum -34、..... を持ちます。

SCSI Manager 4.3 がインストールされている場合は、『Inside Macintosh:Devices』の 4-52 および 4-53 ページの説明にしたがって、SCSILookupRefNumXRef() ルーチンを呼び出します。

SCSI Manager 4.3 が存在するかどうかを検出するには、『Inside Macintosh:Operating System Utilities』の 8-21 から 8-23 ページの例にしたがって、_SCSIAtomic トラップがインプリメントされていないことをチェックします。また、「Tool Chest developer CD」の“SCSI Samples 1.0”フォルダにある "I Am Curious SCSI" ノートを読んでください。

ボリュームリファレンス番号がわかっているとすると、ドライバリファレンス番号を取得する必要があります。この処理を行うには、『Inside Macintosh:Files』の 2-144 ページの説明にしたがって、PBHGetVInfo()を呼び出します。

OSErr GetDRefNumFromVRefNum(short vRefNum, short *dRefNum)
{
	HParamBlockRec pb;
	Str27 volName;
	OSErr result;

	pb.volumeParam.ioVRefNum = vRefNum;
	pb.volumeParam.ioNamePtr = volName;
	pb.volumeParam.ioVolIndex = 0; /* ioVRefNum のみを使用し、
						ボリューム名を返す */ 
	result = PBHGetVInfoSync(&pb);
	if (result == noErr) *dRefNum = pb.volumeParam.ioVDrvInfo;

	return result;

}


ドライバリファレンス番号を取得できたら、
次のコードを使います ("I Am Curious SCSI" より)。

/* * 特定のドライバリファレンス番号に対する SCSI Bus ID を取得する。
これはオリジナルの SCSI Manager に対して有効。非同期 SCSI Manager の場合は、
ドライバは SCSI Manager を使って登録されていないことが必要。 */

#define DriverRefNumToSCSI(x) ((signed short) (~(x) - 32))

/* * 登録されているデバイスのリストを検索して、
特定のドライバに対する DeviceIdent を取得する。
正常に終了すれば noErr が返され、存在しなければ nsvErr が返される。 */

OSErr DriverRefNumToDeviceID( short driverRefNum, 
				DeviceIdent *deviceIdentPtr ) 
{
	OSErr status, scsiStatus;
	SCSI_DriverPB pb;
	short targetID;

	status = nsvErr;

	if (AsynchronousSCSIManagerPresent()) { 

	/* * 登録されているドライバのリストをスキャンして、
	このdriverRefNum を見つける */ 

		ClearMemory((ptr) &pb, sizeof pb);

		pb.scsiPBLength = sizeof (SCSI_Driver_PB);
		pb.scsiCompletion = NULL;
		pb.scsiFlags = 0;
		pb.scsiFunctionCode = SCSILookupRefNumXref;

	/* DeviceIdent の初期値として "不可能な" 値を設定して、
	スキャンプロセスを開始する。
	SCSIAction により、pb.scsiDevice に現在のデバイスが返され、
	pb.scsiNextDevice に次に登録されているデバイスが返される。
	ループ処理を行うことで、登録されている各デバイスを順次検査できる。
	次のデバイスが不正なバス上にあるときはループを抜ける。
	なお、"不正な" 設定値を含む現在のバス (pb.scsiDevice.bus) の
	最初の値は無視する必要がある。 */

		*((long *) &pb.scsiDevice) = -1L;

		do { scsiStatus = SCSIAction((SCSI_PB *) &pb);
		
			if (scsiStatus != noErr) {
				status = scsiStatus;
				break;
			}
			/* 目的のドライブか? */ 
			if (pb.scsiDriver == driverRefNum
			/* これは本当のバスか? */
			&& pb.scsiDevice.bus != 0xFF) { 
				*deviceIdentPtr = pb.scsiDevice;
				status = noErr;
				break;
			}
			pb.scsiDevice = pb.scsiNextDevice;

		} while (pb.scsiDevice.bus != 0xFF);

	}
	if (status == nsvErr) {
	/* * 非同期 SCSI Manager がないか、
	ドライバが SCSI Manager を使って登録されなかった。 */
		targetID = DriverRefNumToSCSI(driverRefNum);
		
		if (targetID >= 0 && targetID <= 6) { 
			deviceIdentPtr->diReserved = 0;
			deviceIdentPtr->diBus = 0;
			deviceIdentPtr->targetID = targetID;
			deviceIdentPtr->LUN = 0;

			status = noErr;
		}

	} return (status);

}
--Brian Bechtel
devsupport@apple.com

[ Technical Q&A's : Devices : DV29 ]