scsi_debug.c

来自「linux 内核源代码」· C语言 代码 · 共 2,078 行 · 第 1/5 页

C
2,078
字号
	num += plen;	return num;}/* SCSI ports VPD page */static int inquiry_evpd_88(unsigned char * arr, int target_dev_id){	int num = 0;	int port_a, port_b;	port_a = target_dev_id + 1;	port_b = port_a + 1;	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x0;	arr[num++] = 0x1;	/* relative port 1 (primary) */	memset(arr + num, 0, 6);	num += 6;	arr[num++] = 0x0;	arr[num++] = 12;	/* length tp descriptor */	/* naa-5 target port identifier (A) */	arr[num++] = 0x61;	/* proto=sas, binary */	arr[num++] = 0x93;	/* PIV=1, target port, NAA */	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x8;	/* length */	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */	arr[num++] = 0x22;	arr[num++] = 0x22;	arr[num++] = 0x20;	arr[num++] = (port_a >> 24);	arr[num++] = (port_a >> 16) & 0xff;	arr[num++] = (port_a >> 8) & 0xff;	arr[num++] = port_a & 0xff;	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x0;	arr[num++] = 0x2;	/* relative port 2 (secondary) */	memset(arr + num, 0, 6);	num += 6;	arr[num++] = 0x0;	arr[num++] = 12;	/* length tp descriptor */	/* naa-5 target port identifier (B) */	arr[num++] = 0x61;	/* proto=sas, binary */	arr[num++] = 0x93;	/* PIV=1, target port, NAA */	arr[num++] = 0x0;	/* reserved */	arr[num++] = 0x8;	/* length */	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */	arr[num++] = 0x22;	arr[num++] = 0x22;	arr[num++] = 0x20;	arr[num++] = (port_b >> 24);	arr[num++] = (port_b >> 16) & 0xff;	arr[num++] = (port_b >> 8) & 0xff;	arr[num++] = port_b & 0xff;	return num;}static unsigned char vpd89_data[] = {/* from 4th byte */ 0,0,0,0,'l','i','n','u','x',' ',' ',' ','S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ','1','2','3','4',0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0xec,0,0,0,0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,0x53,0x41,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x10,0x80,0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,};static int inquiry_evpd_89(unsigned char * arr){	memcpy(arr, vpd89_data, sizeof(vpd89_data));	return sizeof(vpd89_data);}static unsigned char vpdb0_data[] = {	/* from 4th byte */ 0,0,0,4,	0,0,0x4,0,	0,0,0,64,};static int inquiry_evpd_b0(unsigned char * arr){	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));	if (sdebug_store_sectors > 0x400) {		arr[4] = (sdebug_store_sectors >> 24) & 0xff;		arr[5] = (sdebug_store_sectors >> 16) & 0xff;		arr[6] = (sdebug_store_sectors >> 8) & 0xff;		arr[7] = sdebug_store_sectors & 0xff;	}	return sizeof(vpdb0_data);}#define SDEBUG_LONG_INQ_SZ 96#define SDEBUG_MAX_INQ_ARR_SZ 584static int resp_inquiry(struct scsi_cmnd * scp, int target,			struct sdebug_dev_info * devip){	unsigned char pq_pdt;	unsigned char * arr;	unsigned char *cmd = (unsigned char *)scp->cmnd;	int alloc_len, n, ret;	alloc_len = (cmd[3] << 8) + cmd[4];	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);	if (! arr)		return DID_REQUEUE << 16;	if (devip->wlun)		pq_pdt = 0x1e;	/* present, wlun */	else if (scsi_debug_no_lun_0 && (0 == devip->lun))		pq_pdt = 0x7f;	/* not present, no device type */	else		pq_pdt = (scsi_debug_ptype & 0x1f);	arr[0] = pq_pdt;	if (0x2 & cmd[1]) {  /* CMDDT bit set */		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,			       	0);		kfree(arr);		return check_condition_result;	} else if (0x1 & cmd[1]) {  /* EVPD bit set */		int lu_id_num, port_group_id, target_dev_id, len;		char lu_id_str[6];		int host_no = devip->sdbg_host->shost->host_no;				port_group_id = (((host_no + 1) & 0x7f) << 8) +		    (devip->channel & 0x7f);		if (0 == scsi_debug_vpd_use_hostno)			host_no = 0;		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +			    (devip->target * 1000) + devip->lun);		target_dev_id = ((host_no + 1) * 2000) +				 (devip->target * 1000) - 3;		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);		if (0 == cmd[2]) { /* supported vital product data pages */			arr[1] = cmd[2];	/*sanity */			n = 4;			arr[n++] = 0x0;   /* this page */			arr[n++] = 0x80;  /* unit serial number */			arr[n++] = 0x83;  /* device identification */			arr[n++] = 0x84;  /* software interface ident. */			arr[n++] = 0x85;  /* management network addresses */			arr[n++] = 0x86;  /* extended inquiry */			arr[n++] = 0x87;  /* mode page policy */			arr[n++] = 0x88;  /* SCSI ports */			arr[n++] = 0x89;  /* ATA information */			arr[n++] = 0xb0;  /* Block limits (SBC) */			arr[3] = n - 4;	  /* number of supported VPD pages */		} else if (0x80 == cmd[2]) { /* unit serial number */			arr[1] = cmd[2];	/*sanity */			arr[3] = len;			memcpy(&arr[4], lu_id_str, len);		} else if (0x83 == cmd[2]) { /* device identification */			arr[1] = cmd[2];	/*sanity */			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,						 target_dev_id, lu_id_num,						 lu_id_str, len);		} else if (0x84 == cmd[2]) { /* Software interface ident. */			arr[1] = cmd[2];	/*sanity */			arr[3] = inquiry_evpd_84(&arr[4]);		} else if (0x85 == cmd[2]) { /* Management network addresses */			arr[1] = cmd[2];	/*sanity */			arr[3] = inquiry_evpd_85(&arr[4]);		} else if (0x86 == cmd[2]) { /* extended inquiry */			arr[1] = cmd[2];	/*sanity */			arr[3] = 0x3c;	/* number of following entries */			arr[4] = 0x0;   /* no protection stuff */			arr[5] = 0x7;   /* head of q, ordered + simple q's */		} else if (0x87 == cmd[2]) { /* mode page policy */			arr[1] = cmd[2];	/*sanity */			arr[3] = 0x8;	/* number of following entries */			arr[4] = 0x2;	/* disconnect-reconnect mp */			arr[6] = 0x80;	/* mlus, shared */			arr[8] = 0x18;	 /* protocol specific lu */			arr[10] = 0x82;	 /* mlus, per initiator port */		} else if (0x88 == cmd[2]) { /* SCSI Ports */			arr[1] = cmd[2];	/*sanity */			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);		} else if (0x89 == cmd[2]) { /* ATA information */			arr[1] = cmd[2];        /*sanity */			n = inquiry_evpd_89(&arr[4]);			arr[2] = (n >> 8);			arr[3] = (n & 0xff);		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */			arr[1] = cmd[2];        /*sanity */			arr[3] = inquiry_evpd_b0(&arr[4]);		} else {			/* Illegal request, invalid field in cdb */			mk_sense_buffer(devip, ILLEGAL_REQUEST,					INVALID_FIELD_IN_CDB, 0);			kfree(arr);			return check_condition_result;		}		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);		ret = fill_from_dev_buffer(scp, arr,			    min(len, SDEBUG_MAX_INQ_ARR_SZ));		kfree(arr);		return ret;	}	/* drops through here for a standard inquiry */	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */	arr[2] = scsi_debug_scsi_level;	arr[3] = 2;    /* response_data_format==2 */	arr[4] = SDEBUG_LONG_INQ_SZ - 5;	if (0 == scsi_debug_vpd_use_hostno)		arr[5] = 0x10; /* claim: implicit TGPS */	arr[6] = 0x10; /* claim: MultiP */	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */	arr[7] = 0xa; /* claim: LINKED + CMDQUE */	memcpy(&arr[8], inq_vendor_id, 8);	memcpy(&arr[16], inq_product_id, 16);	memcpy(&arr[32], inq_product_rev, 4);	/* version descriptors (2 bytes each) follow */	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */	n = 62;	if (scsi_debug_ptype == 0) {		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */	} else if (scsi_debug_ptype == 1) {		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */	}	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */	ret = fill_from_dev_buffer(scp, arr,			    min(alloc_len, SDEBUG_LONG_INQ_SZ));	kfree(arr);	return ret;}static int resp_requests(struct scsi_cmnd * scp,			 struct sdebug_dev_info * devip){	unsigned char * sbuff;	unsigned char *cmd = (unsigned char *)scp->cmnd;	unsigned char arr[SDEBUG_SENSE_LEN];	int want_dsense;	int len = 18;	memset(arr, 0, sizeof(arr));	if (devip->reset == 1)		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;	sbuff = devip->sense_buff;	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {		if (want_dsense) {			arr[0] = 0x72;			arr[1] = 0x0;		/* NO_SENSE in sense_key */			arr[2] = THRESHOLD_EXCEEDED;			arr[3] = 0xff;		/* TEST set and MRIE==6 */		} else {			arr[0] = 0x70;			arr[2] = 0x0;		/* NO_SENSE in sense_key */			arr[7] = 0xa;   	/* 18 byte sense buffer */			arr[12] = THRESHOLD_EXCEEDED;			arr[13] = 0xff;		/* TEST set and MRIE==6 */		}	} else {		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {			/* DESC bit set and sense_buff in fixed format */			memset(arr, 0, sizeof(arr));			arr[0] = 0x72;			arr[1] = sbuff[2];     /* sense key */			arr[2] = sbuff[12];    /* asc */			arr[3] = sbuff[13];    /* ascq */			len = 8;		}	}	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);	return fill_from_dev_buffer(scp, arr, len);}static int resp_start_stop(struct scsi_cmnd * scp,			   struct sdebug_dev_info * devip){	unsigned char *cmd = (unsigned char *)scp->cmnd;	int power_cond, errsts, start;	if ((errsts = check_readiness(scp, 1, devip)))		return errsts;	power_cond = (cmd[4] & 0xf0) >> 4;	if (power_cond) {		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,			       	0);		return check_condition_result;	}	start = cmd[4] & 1;	if (start == devip->stopped)		devip->stopped = !start;	return 0;}#define SDEBUG_READCAP_ARR_SZ 8static int resp_readcap(struct scsi_cmnd * scp,			struct sdebug_dev_info * devip){	unsigned char arr[SDEBUG_READCAP_ARR_SZ];	unsigned int capac;	int errsts;	if ((errsts = check_readiness(scp, 1, devip)))		return errsts;	/* following just in case virtual_gb changed */	if (scsi_debug_virtual_gb > 0) {		sdebug_capacity = 2048 * 1024;		sdebug_capacity *= scsi_debug_virtual_gb;	} else		sdebug_capacity = sdebug_store_sectors;	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);	if (sdebug_capacity < 0xffffffff) {		capac = (unsigned int)sdebug_capacity - 1;		arr[0] = (capac >> 24);		arr[1] = (capac >> 16) & 0xff;		arr[2] = (capac >> 8) & 0xff;		arr[3] = capac & 0xff;	} else {		arr[0] = 0xff;		arr[1] = 0xff;		arr[2] = 0xff;		arr[3] = 0xff;	}	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;	arr[7] = SECT_SIZE_PER(target) & 0xff;	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);}#define SDEBUG_READCAP16_ARR_SZ 32static int resp_readcap16(struct scsi_cmnd * scp,			  struct sdebug_dev_info * devip){	unsigned char *cmd = (unsigned char *)scp->cmnd;	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];	unsigned long long capac;	int errsts, k, alloc_len;	if ((errsts = check_readiness(scp, 1, devip)))		return errsts;	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)		     + cmd[13]);	/* following just in case virtual_gb changed */	if (scsi_debug_virtual_gb > 0) {		sdebug_capacity = 2048 * 1024;		sdebug_capacity *= scsi_debug_virtual_gb;	} else		sdebug_capacity = sdebug_store_sectors;	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);	capac = sdebug_capacity - 1;	for (k = 0; k < 8; ++k, capac >>= 8)		arr[7 - k] = capac & 0xff;	arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;	arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;	arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;	arr[11] = SECT_SIZE_PER(target) & 0xff;	return fill_from_dev_buffer(scp, arr,				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));}#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412static int resp_report_tgtpgs(struct scsi_cmnd * scp,			      struct sdebug_dev_info * devip){	unsigned char *cmd = (unsigned char *)scp->cmnd;	unsigned char * arr;	int host_no = devip->sdbg_host->shost->host_no;	int n, ret, alen, rlen;	int port_group_a, port_group_b, port_a, port_b;	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)		+ cmd[9]);	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);	if (! arr)		return DID_REQUEUE << 16;	/*	 * EVPD page 0x88 states we have two ports, one	 * real and a fake port with no device connected.	 * So we create two port groups with one port each	 * and set the group with port B to unavailable.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?