⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi.c

📁 create raid tool at linux
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (SEND_COMMAND(sg_dev, cmd) == -1) {	    perror("failed on EVPD Page 0x83 INQUIRY");	    return 1;	}    } while (scsi_retryable_error(sg_dev, cmd, FALSE, DEF_WAIT));    /*     * Get the product ID     */    if(WAS_OK(cmd)) {	i = 4; /* location of the first descriptor */	while(i < cmd.buf[3]) {	    switch(cmd.buf[i + 1] & 0xf) {		case 0:		    sg_dev->id_nonunique = malloc(cmd.buf[i + 3] + 1);		    if(sg_dev->id_nonunique != NULL) {			memcpy(sg_dev->id_nonunique, &cmd.buf[i + 4],			       cmd.buf[i + 3]);			sg_dev->id_nonunique[cmd.buf[i + 3]] = '\0';		    }		    break;		case 1:		    sg_dev->id_vendor = malloc(cmd.buf[i + 3] + 1);		    if(sg_dev->id_vendor != NULL) {			memcpy(sg_dev->id_vendor, &cmd.buf[i + 4],			       cmd.buf[i + 3]);			sg_dev->id_vendor[cmd.buf[i + 3]] = '\0';		    }		    break;		case 2:		    memcpy((void *)&sg_dev->id_eui64[0], &cmd.buf[i + 4], 8);		    break;		case 3:		    memcpy((void *)&sg_dev->id_fcph[0], &cmd.buf[i + 4], 8);		    break;		default:		    break;	    }	    i += cmd.buf[i + 3] + 4;	}    } else if (WAS_SENSE(cmd) && SENSE_KEY(cmd) == ILLEGAL_REQUEST) {	/* the device doesn't support the page requested, don't give an error	 * since this is an optional feature */	return 1;    } else {	printf("%s: scsi error on EVPD Page 0x83 INQUIRY, status byte = 0x%x\n",	       sg_dev->name, STATUS(cmd));	if(WAS_SENSE(cmd)) {		printf("%s: SENSE_KEY 0x%02x, ASC 0x%02x, ASQ 0x%02x\n",			sg_dev->name, SENSE_KEY(cmd), ASC(cmd), ASQ(cmd));	}	return 1;    }    return 0;}/* * Function: scsi_get_serial_number_page * * Inputs: * 	scsi_sg_dev_t * - The sg_dev we want to get size information for * * Outputs: * 	int - 0 on success, 1 on any error or failure. * * Purpose: * 	Used to provide a unique identifier to each device.  This can then * 	be used to detect multipath drives on the fly.  This is the * 	backup method we use when the device doesn't support the device * 	id page.  This isn't quite as reliable as the device id page because * 	we have no assurance from the device that the number we get will * 	be unique, where as several of the options from the device id page * 	are assured of being unique.  Once we get the serial number, which * 	is in ASCII form, we will concatenate it with the device Vendor * 	string, Model string, and Revision string to produce a rather longish, * 	but hopefully unique device id.  It will then be stored in the * 	sg_dev->id_vendor spot. */static intscsi_get_serial_number_page(scsi_sg_dev_t *sg_dev){    scsi_send_command_t cmd;    char *buffer;    /*     * Get the Serial Number page from another INQUIRY command     */    do {	cmd.outsize = 0;	cmd.insize = 255;	memset(cmd.buf, 0, 255);	cmd.buf[0] = INQUIRY;	cmd.buf[1] = 1; /* EVPD bit */	cmd.buf[2] = 0x80; /* Serial Number Page */	cmd.buf[4] = 255;	if (SEND_COMMAND(sg_dev, cmd) == -1) {	    perror("failed on EVPD Page 0x80 INQUIRY");	    return 1;	}    } while (scsi_retryable_error(sg_dev, cmd, FALSE, DEF_WAIT));    /*     * Get the Serial Number and make a string out of it.     */    if(WAS_OK(cmd)) {	buffer = malloc(cmd.buf[3] + 1);	if(buffer == NULL)	    return 1;	strncpy(&buffer[0], &cmd.buf[4], cmd.buf[3]);	buffer[cmd.buf[3]] = '\0';	sg_dev->serial_number = buffer;    } else if (WAS_SENSE(cmd) && SENSE_KEY(cmd) == ILLEGAL_REQUEST) {	/* the device doesn't support the page requested, don't give an error	 * since this is an optional feature */	return 1;    } else {	printf("%s: scsi error on EVPD Page 0x80 INQUIRY, status byte = 0x%x\n",	       sg_dev->name, STATUS(cmd));	if(WAS_SENSE(cmd)) {		printf("%s: SENSE_KEY 0x%02x, ASC 0x%02x, ASQ 0x%02x\n",			sg_dev->name, SENSE_KEY(cmd), ASC(cmd), ASQ(cmd));	}	return 1;    }    return 0;}/* * Function: scsi_init_device_size * * Inputs: * 	scsi_sg_dev_t * - The sg_dev we want to get size information for * * Outputs: * 	int - 0 on success, 1 if the drive is currently reserved, 2 on any * 		other failure. * 	scsi_sg_dev_t * - the size information will be placed into the * 		scsi_sg_dev struct on success. * * Purpose: * 	This was part of scsi_init_sg_device(), but in order to make that * 	function more graceful in the event that the device is currently * 	reserved by another host at the time we are trying to initialize it, * 	we separated this function out.  This is only really needed if you * 	plan to use extent based reservations on less than the whole drive * 	anyway, so it can be skipped entirely if you know that you will only * 	need to reserve whole drives. */intscsi_init_device_size(scsi_sg_dev_t * sg_dev){    scsi_send_command_t cmd;    /*     * Not everything we needed is part of an INQUIRY return.  Next, we     * want to establish the block size for any extent based reservations.     * Try to get block_size and num_blocks first by using a READ_CAPACITY,     * but since that command isn't mandatory in the spec, fall back to     * a MODE_SENSE and general block descriptors if it isn't available.     * If both methods give permanent failures, then assume 512 bytes per     * block and ignore the num_blocks element.     */    do {	cmd.outsize = 0;	cmd.insize = 16;	memset(cmd.buf, 0, 16);	cmd.buf[0] = READ_CAPACITY;	if (SEND_COMMAND(sg_dev, cmd) == -1) {	    perror("failed on READ_CAPACITY");	    return (2);	}    } while (scsi_retryable_error(sg_dev, cmd, FALSE, DEF_WAIT));    if (WAS_SENSE(cmd) && (SENSE_KEY(cmd) == ILLEGAL_REQUEST)) {	do {	    cmd.outsize = 0;	    cmd.insize = 255;	    memset(cmd.buf, 0, 255);	    cmd.buf[0] = MODE_SENSE;	    cmd.buf[4] = 255;	    if (SEND_COMMAND(sg_dev, cmd) == -1) {		perror("failed on MODE_SENSE");		return (2);	    }	} while (scsi_retryable_error(sg_dev, cmd, FALSE, DEF_WAIT));	if (RES_CONFLICT(cmd)) {	    printf("%s: device is currently reserved.\n", sg_dev->name);	    return (1);	} else if (!WAS_OK(cmd) || (cmd.buf[3] != 8)) {	    printf("%s: both MODE_SENSE and READ_CAPACITY failed "		   "to return a block size\n", sg_dev->name);	    printf("\tassuming 512 bytes per block\n");	    sg_dev->block_size = 512;	    sg_dev->num_blocks = 0;	    return (2);	} else {	    sg_dev->num_blocks =		((cmd.buf[4] << 24) | (cmd.buf[5] << 16) | (cmd.buf[6] << 8) |		 cmd.buf[7]);	    sg_dev->block_size =		((cmd.buf[9] << 16) | (cmd.buf[10] << 8) | cmd.buf[11]);	}    } else if (WAS_SENSE(cmd)) {	printf("%s: failure on READ_CAPACITY, SENSE_KEY 0x%02x\n",	       sg_dev->name, SENSE_KEY(cmd));	return (2);    } else if (RES_CONFLICT(cmd)) {	printf("%s: the device is currently reserved.\n", sg_dev->name);	return (1);    } else if (!WAS_OK(cmd)) {	printf("%s: failure on READ_CAPACITY, status byte 0x%02x\n",	       sg_dev->name, STATUS(cmd));	return (2);    } else {	sg_dev->num_blocks =	    1 +	    ((cmd.buf[0] << 24) | (cmd.buf[1] << 16) | (cmd.buf[2] << 8) |	     cmd.buf[3]);	sg_dev->block_size =	    (cmd.buf[4] << 24) | (cmd.buf[5] << 16) | (cmd.						       buf[6] << 8) |	    cmd.buf[7];    }    return (0);}/* * Function: scsi_release_sg_device * * Inputs: * 	scsi_sg_dev_t * - Pointer to the sg_dev structure to be released. * * Outputs: * 	int - On success, 0.  On failure, 1. * * Purpose: * 	This routine will free all current reservations on a device that * 	are listed in the reservations list.  It will then free() any memory * 	that has been malloc()'ed for the sg_name item, close the file * 	descriptor that points to the sg device entry, and then free() the * 	sg_dev struct itself.  The calling program is responsible for * 	closing the file descriptor to the block device (aka, sg_dev->disk_fd) * 	itself.  Since scsi_init_sg_device() doesn't open that file * 	descriptor, but instead simply records the one that was passed in to  * 	it, it was deemed inconsistent for this function to go around closing * 	file descriptors that the init function didn't open().  The calling * 	function is also responsible for calling free() on the sg_dev->name * 	buffer that was passed to scsi_init_sg_device() if appropriate. */intscsi_release_sg_device(scsi_sg_dev_t * sg_dev){    if (sg_dev == NULL)	return (0);    if (sg_dev->sg_name)	free((void *)sg_dev->sg_name);    if (sg_dev->id_nonunique)	free((void *)sg_dev->id_nonunique);    if (sg_dev->id_vendor)	free((void *)sg_dev->id_vendor);    if (sg_dev->serial_number)	free((void *)sg_dev->serial_number);    close(sg_dev->fd);    free(sg_dev);    return (0);}/* * Function: scsi_wait_device_ready * * Inputs: * 	scsi_sg_dev_t * - The device to wait on * 	int - Amount of time to wait (in seconds) before giving up. * * Outputs: * 	int - 0 if device is ready, 1 if we timed out, -1 on error. * * Purpose: * 	This function will spin in a loop waiting for a device to become * 	ready.  It will return when either the device reports that it is * 	ready for use or the timeout has passed, whichever happens first. * */intscsi_wait_device_ready(scsi_sg_dev_t * sg_dev, int timeout){    scsi_send_command_t cmd;    int i;    if (timeout < 0 || timeout > 60) {	printf("%s: wait timeout out of range (%d)\n", sg_dev->name, timeout);	printf("Allowed timeout is between 0 and 60 seconds.\n");	return (-1);    }    i = 0;    do {	if (i)	    usleep(100);	cmd.outsize = 0;	cmd.insize = 16;	memset(cmd.buf, 0, 16);	cmd.buf[0] = TEST_UNIT_READY;	cmd.buf[1] = sg_dev->scsi_dev_lun << 5;	if (SEND_COMMAND(sg_dev, cmd) == -1) {	    perror("failure sending TEST_UNIT_READY");	    return (-1);	}	if (!WAS_SENSE(cmd)) {	    break;	}    } while ((SENSE_KEY(cmd) != NO_SENSE) && (++i < (timeout * 10)));    if (STATUS(cmd) == GOOD || SENSE_KEY(cmd) == NO_SENSE)	return (0);    else	return (1);}

⌨️ 快捷键说明

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