static int get_stream_blocksize(BlockBackend *blk) { uint8_t cmd[6]; uint8_t buf[12]; uint8_t sensebuf[8]; sg_io_hdr_t io_header; int ret; memset(cmd, 0, sizeof(cmd)); memset(buf, 0, sizeof(buf)); cmd[0] = MODE_SENSE; cmd[4] = sizeof(buf); memset(&io_header, 0, sizeof(io_header)); io_header.interface_id = 'S'; io_header.dxfer_direction = SG_DXFER_FROM_DEV; io_header.dxfer_len = sizeof(buf); io_header.dxferp = buf; io_header.cmdp = cmd; io_header.cmd_len = sizeof(cmd); io_header.mx_sb_len = sizeof(sensebuf); io_header.sbp = sensebuf; io_header.timeout = 6000; /* XXX */ ret = blk_ioctl(blk, SG_IO, &io_header); if (ret < 0 || io_header.driver_status || io_header.host_status) { return -1; } return (buf[9] << 16) | (buf[10] << 8) | buf[11]; }
void scsi_generic_read_device_identification(SCSIDevice *s) { uint8_t cmd[6]; uint8_t buf[250]; uint8_t sensebuf[8]; sg_io_hdr_t io_header; int ret; int i, len; memset(cmd, 0, sizeof(cmd)); memset(buf, 0, sizeof(buf)); cmd[0] = INQUIRY; cmd[1] = 1; cmd[2] = 0x83; cmd[4] = sizeof(buf); memset(&io_header, 0, sizeof(io_header)); io_header.interface_id = 'S'; io_header.dxfer_direction = SG_DXFER_FROM_DEV; io_header.dxfer_len = sizeof(buf); io_header.dxferp = buf; io_header.cmdp = cmd; io_header.cmd_len = sizeof(cmd); io_header.mx_sb_len = sizeof(sensebuf); io_header.sbp = sensebuf; io_header.timeout = 6000; /* XXX */ ret = blk_ioctl(s->conf.blk, SG_IO, &io_header); if (ret < 0 || io_header.driver_status || io_header.host_status) { return; } len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4); for (i = 0; i + 3 <= len; ) { const uint8_t *p = &buf[i + 4]; uint64_t wwn; if (i + (p[3] + 4) > len) { break; } if ((p[1] & 0x10) == 0) { /* Associated with the logical unit */ if (read_naa_id(p, &wwn) == 0) { s->wwn = wwn; } } else if ((p[1] & 0x10) == 0x10) { /* Associated with the target port */ if (read_naa_id(p, &wwn) == 0) { s->port_wwn = wwn; } } i += p[3] + 4; } }
static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { struct NFTLrecord *nftl; nftl = NFTLs[MINOR(inode->i_rdev) / 16]; if (!nftl) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; g.heads = nftl->heads; g.sectors = nftl->sectors; g.cylinders = nftl->cylinders; g.start = part_table[MINOR(inode->i_rdev)].start_sect; return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, (long *) arg); case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); if (nftl->mtd->sync) nftl->mtd->sync(nftl->mtd); return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (nftl->usecount > 1) return -EBUSY; #if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) / 16); #else grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) / 16, 1<<4, nftl->nr_sects); #endif return 0; #if (LINUX_VERSION_CODE < 0x20303) RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */ #else case BLKROSET: case BLKROGET: case BLKSSZGET: return blk_ioctl(inode->i_rdev, cmd, arg); #endif default: return -EINVAL; } }
static int pd_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg) { struct hd_geometry *geo = (struct hd_geometry *) arg; int dev, err, unit; if ((!inode) || (!inode->i_rdev)) return -EINVAL; dev = MINOR(inode->i_rdev); unit = DEVICE_NR(inode->i_rdev); if (dev >= PD_DEVS) return -EINVAL; if (!PD.present) return -ENODEV; switch (cmd) { case CDROMEJECT: if (PD.access == 1) pd_eject(unit); return 0; case HDIO_GETGEO: if (!geo) return -EINVAL; err = verify_area(VERIFY_WRITE,geo,sizeof(*geo)); if (err) return err; if (PD.alt_geom) { put_user(PD.capacity/(PD_LOG_HEADS*PD_LOG_SECTS), (short *) &geo->cylinders); put_user(PD_LOG_HEADS, (char *) &geo->heads); put_user(PD_LOG_SECTS, (char *) &geo->sectors); } else { put_user(PD.cylinders, (short *) &geo->cylinders); put_user(PD.heads, (char *) &geo->heads); put_user(PD.sectors, (char *) &geo->sectors); } put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); case BLKGETSIZE: case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: case BLKRAGET: case BLKFLSBUF: case BLKPG: return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } }
int sbull_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err; long size; struct hd_geometry geo; PDEBUG("ioctl 0x%x 0x%lx\n", cmd, arg); switch(cmd) { case BLKGETSIZE: /* Return the device size, expressed in sectors */ if (!arg) return -EINVAL; /* NULL pointer: not valid */ err = ! access_ok (VERIFY_WRITE, arg, sizeof(long)); if (err) return -EFAULT; size = blksize*sbull_sizes[MINOR(inode->i_rdev)] / sbull_hardsects[MINOR(inode->i_rdev)]; __copy_to_user((long *) arg, &size, sizeof (long)); return 0; case BLKRRPART: /* re-read partition table: can't do it */ return -ENOTTY; case HDIO_GETGEO: /* * Get geometry: since we are a virtual device, we have to make * up something plausible. So we claim 16 sectors, four heads, * and calculate the corresponding number of cylinders. We set the * start of data at sector four. */ err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo)); if (err) return -EFAULT; size = sbull_size * blksize / sbull_hardsect; geo.cylinders = (size & ~0x3f) >> 6; geo.heads = 4; geo.sectors = 16; geo.start = 4; __copy_to_user((void *) arg, &geo, sizeof(geo)); return 0; default: /* * For ioctls we don't understand, let the block layer handle them. */ return blk_ioctl(inode->i_rdev, cmd, arg); } return -ENOTTY; /* unknown command */ }
static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int error = -EINVAL; unsigned int minor; if (!inode || !inode->i_rdev) goto out; minor = MINOR(inode->i_rdev); switch (cmd) { case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* special: we want to release the ramdisk memory, it's not like with the other blockdevices where this ioctl only flushes away the buffer cache. */ error = -EBUSY; down(&inode->i_bdev->bd_sem); if (inode->i_bdev->bd_openers <= 2) { truncate_inode_pages(inode->i_mapping, 0); error = 0; } up(&inode->i_bdev->bd_sem); break; case BLKGETSIZE: /* Return device size */ if (!arg) break; error = put_user(rd_kbsize[minor] << 1, (unsigned long *) arg); break; case BLKGETSIZE64: error = put_user((u64)rd_kbsize[minor]<<10, (u64*)arg); break; case BLKROSET: case BLKROGET: case BLKSSZGET: error = blk_ioctl(inode->i_rdev, cmd, arg); }; out: return error; }
static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { struct NFTLrecord *nftl; int p; nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS]; if (!nftl) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; g.heads = nftl->heads; g.sectors = nftl->sectors; g.cylinders = nftl->cylinders; g.start = part_table[MINOR(inode->i_rdev)].start_sect; return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } case BLKGETSIZE: /* Return device size */ return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, (unsigned long *) arg); #ifdef BLKGETSIZE64 case BLKGETSIZE64: return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *)arg); #endif case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); if (nftl->mtd->sync) nftl->mtd->sync(nftl->mtd); return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (nftl->usecount > 1) return -EBUSY; /* * We have to flush all buffers and invalidate caches, * or we won't be able to re-use the partitions, * if there was a change and we don't want to reboot */ p = (1<<NFTL_PARTN_BITS) - 1; while (p-- > 0) { kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p); if (part_table[p].nr_sects > 0) invalidate_device (devp, 1); part_table[MINOR(inode->i_dev)+p].start_sect = 0; part_table[MINOR(inode->i_dev)+p].nr_sects = 0; } #if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS); #else grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS, 1<<NFTL_PARTN_BITS, nftl->nr_sects); #endif return 0; #if (LINUX_VERSION_CODE < 0x20303) RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */ #else case BLKROSET: case BLKROGET: case BLKSSZGET: return blk_ioctl(inode->i_rdev, cmd, arg); #endif default: return -EINVAL; } }
static void scsi_generic_realize(SCSIDevice *s, Error **errp) { int rc; int sg_version; struct sg_scsi_id scsiid; if (!s->conf.blk) { error_setg(errp, "drive property not set"); return; } if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_setg(errp, "Device doesn't support drive option werror"); return; } if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_setg(errp, "Device doesn't support drive option rerror"); return; } /* check we are using a driver managing SG_IO (version 3 and after */ rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { error_setg(errp, "cannot get SG_IO version number: %s. " "Is this a SCSI device?", strerror(-rc)); return; } if (sg_version < 30000) { error_setg(errp, "scsi generic interface too old"); return; } /* get LUN of the /dev/sg? */ if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); return; } /* define device state */ s->type = scsiid.scsi_type; DPRINTF("device type %d\n", s->type); switch (s->type) { case TYPE_TAPE: s->blocksize = get_stream_blocksize(s->conf.blk); if (s->blocksize == -1) { s->blocksize = 0; } break; /* Make a guess for block devices, we'll fix it when the guest sends. * READ CAPACITY. If they don't, they likely would assume these sizes * anyway. (TODO: they could also send MODE SENSE). */ case TYPE_ROM: case TYPE_WORM: s->blocksize = 2048; break; default: s->blocksize = 512; break; } DPRINTF("block size %d\n", s->blocksize); }
/*! j'ai récupérée quasi intégralement le code de sbull.c, j'ai juste adapté certains noms de fonction Ca permet d'avoir une fonction bien testée et débuggée */ int smd_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err, size; struct hd_geometry *geo = (struct hd_geometry *)arg; servernode_t *sn; ndevice_t *nd; nd = minor2ndev[MINOR(inode->i_rdev)]; sn = nd->sn; PDEBUG("cmd=0x%x arg=0x%lx ndev='%s:%s'\n", cmd, arg, sn->name, nd->name); switch(cmd) { case BLKGETSIZE: /* Return the device size, expressed in sectors */ if (!arg) return -EINVAL; /* NULL pointer: not valid */ err=verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); if (err) return err; put_user(nd->size * (1024 / SMD_HARDSECT), (long *) arg); PDEBUG("BLKGETSIZE %lld (device size %lld, sect size %d)\n", nd->size * (1024 / SMD_HARDSECT), nd->size, SMD_HARDSECT ); return 0; case BLKFLSBUF: /* flush */ if (!suser()) return -EACCES; /* only root */ fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); PDEBUG("BLKFLSBUF \n"); return 0; case BLKRAGET: /* return the readahead value */ if (!arg) return -EINVAL; err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); if (err) return err; put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); PDEBUG("BLKRAGET \n"); return 0; case BLKRASET: /* set the readahead value */ if (!suser()) return -EACCES; if (arg > 0xff) return -EINVAL; /* limit it */ read_ahead[MAJOR(inode->i_rdev)] = arg; PDEBUG("BLKRASET \n"); return 0; case BLKRRPART: /* re-read partition table: can't do it */ PDEBUG("BLKRRPART \n"); return -EINVAL; //RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations */ case HDIO_GETGEO: /* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ size = nd->size * (1024 / SMD_HARDSECT); size &= ~0x3f; /* multiple of 64 */ if (geo==NULL) return -EINVAL; err = verify_area(VERIFY_WRITE, geo, sizeof(*geo)); if (err) return err; put_user(size >> 6, &geo->cylinders); put_user( 4, &geo->heads); put_user( 16, &geo->sectors); put_user( 4, &geo->start); PDEBUG("HDIO_GETGEO \n"); return 0; default: PDEBUG("PAR DEFAUT \n"); return blk_ioctl(inode->i_rdev, cmd, arg); } PDEBUG("COMMANDE INCONNUE \n"); return -EINVAL; /* unknown command */ }
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg) { int dev; if ((!inode) || !(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); if (dev >= xd_drives) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; struct hd_geometry *geometry = (struct hd_geometry *) arg; g.heads = xd_info[dev].heads; g.sectors = xd_info[dev].sectors; g.cylinders = xd_info[dev].cylinders; g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; nodma = !arg; if (nodma && xd_dma_buffer) { xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); xd_dma_buffer = 0; } else if (!nodma && !xd_dma_buffer) { xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); if (!xd_dma_buffer) { nodma = XD_DONT_USE_DMA; return -ENOMEM; } } return 0; case HDIO_GET_DMA: return put_user(!nodma, (long *) arg); case HDIO_GET_MULTCOUNT: return put_user(xd_maxsectors, (long *) arg); case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return xd_reread_partitions(inode->i_rdev); case BLKGETSIZE: case BLKGETSIZE64: case BLKFLSBUF: case BLKROSET: case BLKROGET: case BLKRASET: case BLKRAGET: case BLKPG: return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } }
static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { kdev_t dev = inode->i_rdev; struct Scsi_Host * host; Scsi_Device * SDev; int diskinfo[4]; SDev = rscsi_disks[DEVICE_NR(dev)].device; if (!SDev) return -ENODEV; /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ if( !scsi_block_when_processing_errors(SDev) ) { return -ENODEV; } switch (cmd) { case HDIO_GETGEO: /* Return BIOS disk parameters */ { struct hd_geometry *loc = (struct hd_geometry *) arg; if(!loc) return -EINVAL; host = rscsi_disks[DEVICE_NR(dev)].device->host; /* default to most commonly used values */ diskinfo[0] = 0x40; diskinfo[1] = 0x20; diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; /* override with calculated, extended default, or driver values */ if(host->hostt->bios_param != NULL) host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); if (put_user(diskinfo[0], &loc->heads) || put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[2], &loc->cylinders) || put_user(sd_gendisks[SD_MAJOR_IDX( inode->i_rdev)].part[MINOR( inode->i_rdev)].start_sect, &loc->start)) return -EFAULT; return 0; } case HDIO_GETGEO_BIG: { struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; if(!loc) return -EINVAL; host = rscsi_disks[DEVICE_NR(dev)].device->host; /* default to most commonly used values */ diskinfo[0] = 0x40; diskinfo[1] = 0x20; diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; /* override with calculated, extended default, or driver values */ if(host->hostt->bios_param != NULL) host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); if (put_user(diskinfo[0], &loc->heads) || put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || put_user(sd_gendisks[SD_MAJOR_IDX( inode->i_rdev)].part[MINOR( inode->i_rdev)].start_sect, &loc->start)) return -EFAULT; return 0; } case BLKGETSIZE: case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: case BLKRAGET: case BLKFLSBUF: case BLKSSZGET: case BLKPG: case BLKELVGET: case BLKELVSET: case BLKBSZGET: case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_scsidisk(dev, 1); default: return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); } }