aachba.c

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

C
2,197
字号
	/*	 *	Check that the command queued to the controller	 */	if (status == -EINPROGRESS) {		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;		return 0;	}			printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);	aac_fib_complete(cmd_fibcontext);	aac_fib_free(cmd_fibcontext);	return -1;}static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd){	struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;	if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))		return aac_scsi_cmd(scsicmd);	scsicmd->result = DID_NO_CONNECT << 16;	scsicmd->scsi_done(scsicmd);	return 0;}static void _aac_probe_container2(void * context, struct fib * fibptr){	struct fsa_dev_info *fsa_dev_ptr;	int (*callback)(struct scsi_cmnd *);	struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;	if (!aac_valid_context(scsicmd, fibptr))		return;	scsicmd->SCp.Status = 0;	fsa_dev_ptr = fibptr->dev->fsa_dev;	if (fsa_dev_ptr) {		struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);		fsa_dev_ptr += scmd_id(scsicmd);		if ((le32_to_cpu(dresp->status) == ST_OK) &&		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {			fsa_dev_ptr->valid = 1;			fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);			fsa_dev_ptr->size			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);			fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);		}		if ((fsa_dev_ptr->valid & 1) == 0)			fsa_dev_ptr->valid = 0;		scsicmd->SCp.Status = le32_to_cpu(dresp->count);	}	aac_fib_complete(fibptr);	aac_fib_free(fibptr);	callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);	scsicmd->SCp.ptr = NULL;	(*callback)(scsicmd);	return;}static void _aac_probe_container1(void * context, struct fib * fibptr){	struct scsi_cmnd * scsicmd;	struct aac_mount * dresp;	struct aac_query_mount *dinfo;	int status;	dresp = (struct aac_mount *) fib_data(fibptr);	dresp->mnt[0].capacityhigh = 0;	if ((le32_to_cpu(dresp->status) != ST_OK) ||	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {		_aac_probe_container2(context, fibptr);		return;	}	scsicmd = (struct scsi_cmnd *) context;	if (!aac_valid_context(scsicmd, fibptr))		return;	aac_fib_init(fibptr);	dinfo = (struct aac_query_mount *)fib_data(fibptr);	dinfo->command = cpu_to_le32(VM_NameServe64);	dinfo->count = cpu_to_le32(scmd_id(scsicmd));	dinfo->type = cpu_to_le32(FT_FILESYS);	status = aac_fib_send(ContainerCommand,			  fibptr,			  sizeof(struct aac_query_mount),			  FsaNormal,			  0, 1,			  _aac_probe_container2,			  (void *) scsicmd);	/*	 *	Check that the command queued to the controller	 */	if (status == -EINPROGRESS)		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;	else if (status < 0) {		/* Inherit results from VM_NameServe, if any */		dresp->status = cpu_to_le32(ST_OK);		_aac_probe_container2(context, fibptr);	}}static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)){	struct fib * fibptr;	int status = -ENOMEM;	if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {		struct aac_query_mount *dinfo;		aac_fib_init(fibptr);		dinfo = (struct aac_query_mount *)fib_data(fibptr);		dinfo->command = cpu_to_le32(VM_NameServe);		dinfo->count = cpu_to_le32(scmd_id(scsicmd));		dinfo->type = cpu_to_le32(FT_FILESYS);		scsicmd->SCp.ptr = (char *)callback;		status = aac_fib_send(ContainerCommand,			  fibptr,			  sizeof(struct aac_query_mount),			  FsaNormal,			  0, 1,			  _aac_probe_container1,			  (void *) scsicmd);		/*		 *	Check that the command queued to the controller		 */		if (status == -EINPROGRESS) {			scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;			return 0;		}		if (status < 0) {			scsicmd->SCp.ptr = NULL;			aac_fib_complete(fibptr);			aac_fib_free(fibptr);		}	}	if (status < 0) {		struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;		if (fsa_dev_ptr) {			fsa_dev_ptr += scmd_id(scsicmd);			if ((fsa_dev_ptr->valid & 1) == 0) {				fsa_dev_ptr->valid = 0;				return (*callback)(scsicmd);			}		}	}	return status;}/** *	aac_probe_container		-	query a logical volume *	@dev: device to query *	@cid: container identifier * *	Queries the controller about the given volume. The volume information *	is updated in the struct fsa_dev_info structure rather than returned. */static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd){	scsicmd->device = NULL;	return 0;}int aac_probe_container(struct aac_dev *dev, int cid){	struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);	struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);	int status;	if (!scsicmd || !scsidev) {		kfree(scsicmd);		kfree(scsidev);		return -ENOMEM;	}	scsicmd->list.next = NULL;	scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;	scsicmd->device = scsidev;	scsidev->sdev_state = 0;	scsidev->id = cid;	scsidev->host = dev->scsi_host_ptr;	if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)		while (scsicmd->device == scsidev)			schedule();	kfree(scsidev);	status = scsicmd->SCp.Status;	kfree(scsicmd);	return status;}/* Local Structure to set SCSI inquiry data strings */struct scsi_inq {	char vid[8];         /* Vendor ID */	char pid[16];        /* Product ID */	char prl[4];         /* Product Revision Level */};/** *	InqStrCopy	-	string merge *	@a:	string to copy from *	@b:	string to copy to * * 	Copy a String from one location to another *	without copying \0 */static void inqstrcpy(char *a, char *b){	while(*a != (char)0) 		*b++ = *a++;}static char *container_types[] = {        "None",        "Volume",        "Mirror",        "Stripe",        "RAID5",        "SSRW",        "SSRO",        "Morph",        "Legacy",        "RAID4",        "RAID10",                     "RAID00",                     "V-MIRRORS",                  "PSEUDO R4",          	"RAID50",	"RAID5D",	"RAID5D0",	"RAID1E",	"RAID6",	"RAID60",        "Unknown"};/* Function: setinqstr * * Arguments: [1] pointer to void [1] int * * Purpose: Sets SCSI inquiry data strings for vendor, product * and revision level. Allows strings to be set in platform dependant * files instead of in OS dependant driver source. */static void setinqstr(struct aac_dev *dev, void *data, int tindex){	struct scsi_inq *str;	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */	memset(str, ' ', sizeof(*str));	if (dev->supplement_adapter_info.AdapterTypeText[0]) {		char * cp = dev->supplement_adapter_info.AdapterTypeText;		int c = sizeof(str->vid);		while (*cp && *cp != ' ' && --c)			++cp;		c = *cp;		*cp = '\0';		inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,		  str->vid); 		*cp = c;		while (*cp && *cp != ' ')			++cp;		while (*cp == ' ')			++cp;		/* last six chars reserved for vol type */		c = 0;		if (strlen(cp) > sizeof(str->pid)) {			c = cp[sizeof(str->pid)];			cp[sizeof(str->pid)] = '\0';		}		inqstrcpy (cp, str->pid);		if (c)			cp[sizeof(str->pid)] = c;	} else {		struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);		inqstrcpy (mp->vname, str->vid);		/* last six chars reserved for vol type */		inqstrcpy (mp->model, str->pid);	}	if (tindex < ARRAY_SIZE(container_types)){		char *findit = str->pid;		for ( ; *findit != ' '; findit++); /* walk till we find a space */		/* RAID is superfluous in the context of a RAID device */		if (memcmp(findit-4, "RAID", 4) == 0)			*(findit -= 4) = ' ';		if (((findit - str->pid) + strlen(container_types[tindex]))		 < (sizeof(str->pid) + sizeof(str->prl)))			inqstrcpy (container_types[tindex], findit + 1);	}	inqstrcpy ("V1.0", str->prl);}static void get_container_serial_callback(void *context, struct fib * fibptr){	struct aac_get_serial_resp * get_serial_reply;	struct scsi_cmnd * scsicmd;	BUG_ON(fibptr == NULL);	scsicmd = (struct scsi_cmnd *) context;	if (!aac_valid_context(scsicmd, fibptr))		return;	get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);	/* Failure is irrelevant, using default value instead */	if (le32_to_cpu(get_serial_reply->status) == CT_OK) {		char sp[13];		/* EVPD bit set */		sp[0] = INQD_PDT_DA;		sp[1] = scsicmd->cmnd[2];		sp[2] = 0;		sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",		  le32_to_cpu(get_serial_reply->uid));		aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));	}	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;	aac_fib_complete(fibptr);	aac_fib_free(fibptr);	scsicmd->scsi_done(scsicmd);}/** *	aac_get_container_serial - get container serial, none blocking. */static int aac_get_container_serial(struct scsi_cmnd * scsicmd){	int status;	struct aac_get_serial *dinfo;	struct fib * cmd_fibcontext;	struct aac_dev * dev;	dev = (struct aac_dev *)scsicmd->device->host->hostdata;	if (!(cmd_fibcontext = aac_fib_alloc(dev)))		return -ENOMEM;	aac_fib_init(cmd_fibcontext);	dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);	dinfo->command = cpu_to_le32(VM_ContainerConfig);	dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));	status = aac_fib_send(ContainerCommand,		  cmd_fibcontext,		  sizeof (struct aac_get_serial),		  FsaNormal,		  0, 1,		  (fib_callback) get_container_serial_callback,		  (void *) scsicmd);	/*	 *	Check that the command queued to the controller	 */	if (status == -EINPROGRESS) {		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;		return 0;	}	printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);	aac_fib_complete(cmd_fibcontext);	aac_fib_free(cmd_fibcontext);	return -1;}/* Function: setinqserial * * Arguments: [1] pointer to void [1] int * * Purpose: Sets SCSI Unit Serial number. *          This is a fake. We should read a proper *          serial number from the container. <SuSE>But *          without docs it's quite hard to do it :-) *          So this will have to do in the meantime.</SuSE> */static int setinqserial(struct aac_dev *dev, void *data, int cid){	/*	 *	This breaks array migration.	 */	return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",			le32_to_cpu(dev->adapter_info.serial[0]), cid);}static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,		      u8 a_sense_code, u8 incorrect_length,		      u8 bit_pointer, u16 field_pointer,		      u32 residue){	sense_buf[0] = 0xF0;	/* Sense data valid, err code 70h (current error) */	sense_buf[1] = 0;	/* Segment number, always zero */	if (incorrect_length) {		sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */		sense_buf[3] = BYTE3(residue);		sense_buf[4] = BYTE2(residue);		sense_buf[5] = BYTE1(residue);		sense_buf[6] = BYTE0(residue);	} else		sense_buf[2] = sense_key;	/* Sense key */	if (sense_key == ILLEGAL_REQUEST)		sense_buf[7] = 10;	/* Additional sense length */	else		sense_buf[7] = 6;	/* Additional sense length */	sense_buf[12] = sense_code;	/* Additional sense code */	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */	if (sense_key == ILLEGAL_REQUEST) {		sense_buf[15] = 0;		if (sense_code == SENCODE_INVALID_PARAM_FIELD)			sense_buf[15] = 0x80;/* Std sense key specific field */		/* Illegal parameter is in the parameter block */		if (sense_code == SENCODE_INVALID_CDB_FIELD)			sense_buf[15] = 0xc0;/* Std sense key specific field */

⌨️ 快捷键说明

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