scsi_debug.c

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

C
2,078
字号
	 */	port_a = 0x1; /* relative port A */	port_b = 0x2; /* relative port B */	port_group_a = (((host_no + 1) & 0x7f) << 8) +	    (devip->channel & 0x7f);	port_group_b = (((host_no + 1) & 0x7f) << 8) +	    (devip->channel & 0x7f) + 0x80;	/*	 * The asymmetric access state is cycled according to the host_id.	 */	n = 4;	if (0 == scsi_debug_vpd_use_hostno) {	    arr[n++] = host_no % 3; /* Asymm access state */	    arr[n++] = 0x0F; /* claim: all states are supported */	} else {	    arr[n++] = 0x0; /* Active/Optimized path */	    arr[n++] = 0x01; /* claim: only support active/optimized paths */	}	arr[n++] = (port_group_a >> 8) & 0xff;	arr[n++] = port_group_a & 0xff;	arr[n++] = 0;    /* Reserved */	arr[n++] = 0;    /* Status code */	arr[n++] = 0;    /* Vendor unique */	arr[n++] = 0x1;  /* One port per group */	arr[n++] = 0;    /* Reserved */	arr[n++] = 0;    /* Reserved */	arr[n++] = (port_a >> 8) & 0xff;	arr[n++] = port_a & 0xff;	arr[n++] = 3;    /* Port unavailable */	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */	arr[n++] = (port_group_b >> 8) & 0xff;	arr[n++] = port_group_b & 0xff;	arr[n++] = 0;    /* Reserved */	arr[n++] = 0;    /* Status code */	arr[n++] = 0;    /* Vendor unique */	arr[n++] = 0x1;  /* One port per group */	arr[n++] = 0;    /* Reserved */	arr[n++] = 0;    /* Reserved */	arr[n++] = (port_b >> 8) & 0xff;	arr[n++] = port_b & 0xff;	rlen = n - 4;	arr[0] = (rlen >> 24) & 0xff;	arr[1] = (rlen >> 16) & 0xff;	arr[2] = (rlen >> 8) & 0xff;	arr[3] = rlen & 0xff;	/*	 * Return the smallest value of either	 * - The allocated length	 * - The constructed command length	 * - The maximum array size	 */	rlen = min(alen,n);	ret = fill_from_dev_buffer(scp, arr,				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));	kfree(arr);	return ret;}/* <<Following mode page info copied from ST318451LW>> */static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target){	/* Read-Write Error Recovery page for mode_sense */	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,					5, 0, 0xff, 0xff};	memcpy(p, err_recov_pg, sizeof(err_recov_pg));	if (1 == pcontrol)		memset(p + 2, 0, sizeof(err_recov_pg) - 2);	return sizeof(err_recov_pg);}static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target){ 	/* Disconnect-Reconnect page for mode_sense */	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,					 0, 0, 0, 0, 0, 0, 0, 0};	memcpy(p, disconnect_pg, sizeof(disconnect_pg));	if (1 == pcontrol)		memset(p + 2, 0, sizeof(disconnect_pg) - 2);	return sizeof(disconnect_pg);}static int resp_format_pg(unsigned char * p, int pcontrol, int target){       /* Format device page for mode_sense */        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,                                     0, 0, 0, 0, 0, 0, 0, 0,                                     0, 0, 0, 0, 0x40, 0, 0, 0};        memcpy(p, format_pg, sizeof(format_pg));        p[10] = (sdebug_sectors_per >> 8) & 0xff;        p[11] = sdebug_sectors_per & 0xff;        p[12] = (SECT_SIZE >> 8) & 0xff;        p[13] = SECT_SIZE & 0xff;        if (DEV_REMOVEABLE(target))                p[20] |= 0x20; /* should agree with INQUIRY */        if (1 == pcontrol)                memset(p + 2, 0, sizeof(format_pg) - 2);        return sizeof(format_pg);}static int resp_caching_pg(unsigned char * p, int pcontrol, int target){ 	/* Caching page for mode_sense */	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};	memcpy(p, caching_pg, sizeof(caching_pg));	if (1 == pcontrol)		memset(p + 2, 0, sizeof(caching_pg) - 2);	return sizeof(caching_pg);}static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target){ 	/* Control mode page for mode_sense */	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,				        0, 0, 0, 0};	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,				     0, 0, 0x2, 0x4b};	if (scsi_debug_dsense)		ctrl_m_pg[2] |= 0x4;	else		ctrl_m_pg[2] &= ~0x4;	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));	if (1 == pcontrol)		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));	else if (2 == pcontrol)		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));	return sizeof(ctrl_m_pg);}static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target){	/* Informational Exceptions control mode page for mode_sense */	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,				       0, 0, 0x0, 0x0};	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,				      0, 0, 0x0, 0x0};	memcpy(p, iec_m_pg, sizeof(iec_m_pg));	if (1 == pcontrol)		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));	else if (2 == pcontrol)		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));	return sizeof(iec_m_pg);}static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target){	/* SAS SSP mode page - short format for mode_sense */	unsigned char sas_sf_m_pg[] = {0x19, 0x6,		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));	if (1 == pcontrol)		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);	return sizeof(sas_sf_m_pg);}static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,			      int target_dev_id){	/* SAS phy control and discover mode page for mode_sense */	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,		    0x2, 0, 0, 0, 0, 0, 0, 0,		    0x88, 0x99, 0, 0, 0, 0, 0, 0,		    0, 0, 0, 0, 0, 0, 0, 0,		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,		    0x3, 0, 0, 0, 0, 0, 0, 0,		    0x88, 0x99, 0, 0, 0, 0, 0, 0,		    0, 0, 0, 0, 0, 0, 0, 0,		};	int port_a, port_b;	port_a = target_dev_id + 1;	port_b = port_a + 1;	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));	p[20] = (port_a >> 24);	p[21] = (port_a >> 16) & 0xff;	p[22] = (port_a >> 8) & 0xff;	p[23] = port_a & 0xff;	p[48 + 20] = (port_b >> 24);	p[48 + 21] = (port_b >> 16) & 0xff;	p[48 + 22] = (port_b >> 8) & 0xff;	p[48 + 23] = port_b & 0xff;	if (1 == pcontrol)		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);	return sizeof(sas_pcd_m_pg);}static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol){	/* SAS SSP shared protocol specific port mode subpage */	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,		    0, 0, 0, 0, 0, 0, 0, 0,		};	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));	if (1 == pcontrol)		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);	return sizeof(sas_sha_m_pg);}#define SDEBUG_MAX_MSENSE_SZ 256static int resp_mode_sense(struct scsi_cmnd * scp, int target,			   struct sdebug_dev_info * devip){	unsigned char dbd, llbaa;	int pcontrol, pcode, subpcode, bd_len;	unsigned char dev_spec;	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;	unsigned char * ap;	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];	unsigned char *cmd = (unsigned char *)scp->cmnd;	if ((errsts = check_readiness(scp, 1, devip)))		return errsts;	dbd = !!(cmd[1] & 0x8);	pcontrol = (cmd[2] & 0xc0) >> 6;	pcode = cmd[2] & 0x3f;	subpcode = cmd[3];	msense_6 = (MODE_SENSE == cmd[0]);	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);	if ((0 == scsi_debug_ptype) && (0 == dbd))		bd_len = llbaa ? 16 : 8;	else		bd_len = 0;	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);	if (0x3 == pcontrol) {  /* Saving values not supported */		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,			       	0);		return check_condition_result;	}	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +			(devip->target * 1000) - 3;	/* set DPOFUA bit for disks */	if (0 == scsi_debug_ptype)		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;	else		dev_spec = 0x0;	if (msense_6) {		arr[2] = dev_spec;		arr[3] = bd_len;		offset = 4;	} else {		arr[3] = dev_spec;		if (16 == bd_len)			arr[4] = 0x1;	/* set LONGLBA bit */		arr[7] = bd_len;	/* assume 255 or less */		offset = 8;	}	ap = arr + offset;	if ((bd_len > 0) && (0 == sdebug_capacity)) {		if (scsi_debug_virtual_gb > 0) {			sdebug_capacity = 2048 * 1024;			sdebug_capacity *= scsi_debug_virtual_gb;		} else			sdebug_capacity = sdebug_store_sectors;	}	if (8 == bd_len) {		if (sdebug_capacity > 0xfffffffe) {			ap[0] = 0xff;			ap[1] = 0xff;			ap[2] = 0xff;			ap[3] = 0xff;		} else {			ap[0] = (sdebug_capacity >> 24) & 0xff;			ap[1] = (sdebug_capacity >> 16) & 0xff;			ap[2] = (sdebug_capacity >> 8) & 0xff;			ap[3] = sdebug_capacity & 0xff;		}        	ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;        	ap[7] = SECT_SIZE_PER(target) & 0xff;		offset += bd_len;		ap = arr + offset;	} else if (16 == bd_len) {		unsigned long long capac = sdebug_capacity;        	for (k = 0; k < 8; ++k, capac >>= 8)                	ap[7 - k] = capac & 0xff;        	ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;        	ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;        	ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;        	ap[15] = SECT_SIZE_PER(target) & 0xff;		offset += bd_len;		ap = arr + offset;	}	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {		/* TODO: Control Extension page */		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,			       	0);		return check_condition_result;	}	switch (pcode) {	case 0x1:	/* Read-Write error recovery page, direct access */		len = resp_err_recov_pg(ap, pcontrol, target);		offset += len;		break;	case 0x2:	/* Disconnect-Reconnect page, all devices */		len = resp_disconnect_pg(ap, pcontrol, target);		offset += len;		break;        case 0x3:       /* Format device page, direct access */                len = resp_format_pg(ap, pcontrol, target);                offset += len;                break;	case 0x8:	/* Caching page, direct access */		len = resp_caching_pg(ap, pcontrol, target);		offset += len;		break;	case 0xa:	/* Control Mode page, all devices */		len = resp_ctrl_m_pg(ap, pcontrol, target);		offset += len;		break;	case 0x19:	/* if spc==1 then sas phy, control+discover */		if ((subpcode > 0x2) && (subpcode < 0xff)) {		        mk_sense_buffer(devip, ILLEGAL_REQUEST,					INVALID_FIELD_IN_CDB, 0);			return check_condition_result;	        }		len = 0;		if ((0x0 == subpcode) || (0xff == subpcode))			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);		if ((0x1 == subpcode) || (0xff == subpcode))			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,						  target_dev_id);		if ((0x2 == subpcode) || (0xff == subpcode))			len += resp_sas_sha_m_spg(ap + len, pcontrol);		offset += len;		break;	case 0x1c:	/* Informational Exceptions Mode page, all devices */		len = resp_iec_m_pg(ap, pcontrol, target);		offset += len;		break;	case 0x3f:	/* Read all Mode pages */		if ((0 == subpcode) || (0xff == subpcode)) {			len = resp_err_recov_pg(ap, pcontrol, target);			len += resp_disconnect_pg(ap + len, pcontrol, target);			len += resp_format_pg(ap + len, pcontrol, target);			len += resp_caching_pg(ap + len, pcontrol, target);			len += resp_ctrl_m_pg(ap + len, pcontrol, target);			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);			if (0xff == subpcode) {				len += resp_sas_pcd_m_spg(ap + len, pcontrol,						  target, target_dev_id);				len += resp_sas_sha_m_spg(ap + len, pcontrol);			}			len += resp_iec_m_pg(ap + len, pcontrol, target);		} else {			mk_sense_buffer(devip, ILLEGAL_REQUEST,					INVALID_FIELD_IN_CDB, 0);			return check_condition_result;                }		offset += len;		break;	default:		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,			       	0);		return check_condition_result;	}	if (msense_6)		arr[0] = offset - 1;	else {		arr[0] = ((offset - 2) >> 8) & 0xff;		arr[1] = (offset - 2) & 0xff;	}	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));}#define SDEBUG_MAX_MSELECT_SZ 512static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,			    struct sdebug_dev_info * devip){	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;	int param_len, res, errsts, mpage;	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];	unsigned char *cmd = (unsigned char *)scp->cmnd;	if ((errsts = check_readiness(scp, 1, devip)))		return errsts;	memset(arr, 0, sizeof(arr));	pf = cmd[1] & 0x10;	sp = cmd[1] & 0x1;	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {		mk_sense_buffer(devip, ILLEGAL_REQUEST,				INVALID_FIELD_IN_CDB, 0);		return check_condition_result;	}        res = fetch_to_dev_buffer(scp, arr, param_len);        if (-1 == res)                return (DID_ERROR << 16);        else if ((res < param_len) &&                 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))                printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "                       " IO sent=%d bytes\n", param_len, res);	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);	if (md_len > 2) {		mk_sense_buffer(devip, ILLEGAL_REQUEST,				INVALID_FIELD_IN_PARAM_LIST, 0);		return check_condition_result;	}	off = bd_len + (mselect6 ? 4 : 8);	mpage = arr[off] & 0x3f;	ps = !!(arr[off] & 0x80);	if (ps) {

⌨️ 快捷键说明

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