Пример #1
0
/* Returns number of sectors written */
int pio_write_buffer_to_swap(const u8* buf, unsigned int size, int secoffset,
	u32 *csum) {
	struct block_device *bdev = NULL;
	struct gendisk *gp = NULL;
	struct scsi_disk *sdkp = NULL;
	struct scsi_device *sdev = NULL;
	struct ata_port *ap = NULL;
	struct ata_device *dev = NULL;
        int written_sect;
	
	unsigned long tsector;

        if( (bdev = bdget(MKDEV(SWAPFS_MAJOR, SWAPFS_MINOR))) != NULL )
        { 
                if( (gp = bdev->bd_disk) != NULL){
                        if ((sdkp = scsi_disk_get(gp)) == NULL){
                                return -ENXIO;
                        }
                }
                else{
                        return -ENODEV;
                }
        }
        else{
                return -ENODEV;
        }

        if((sdev = scsi_dev_get(sdkp)) == NULL)
        {
                return -ENXIO;
        }

        ap = ata_shost_to_port(sdev->host);
	dev = ata_scsi_find_dev(ap, sdev);	  	   

        if( ap == NULL || dev == NULL ){
                return -ENXIO;
        }

	/*
	 * We adjust secoffset to write to the last 1MB of the device,
	 * this is because we don't want to rebuild swap mostly, and
	 * because we can use "lspanic" to grab the last tivo panic.
	 *
	 * We will track which one we've logged by bit-inverting
	 * the checksum.
	 *
	 */
    /* disk_get_part() increments ref count so need to release */
    struct hd_struct *hd_info = disk_get_part(gp, SWAPFS_MINOR);
	/* Partition must be at least 2 MB */
	if(hd_info->nr_sects < (2* 1024 * 1024 / 512)){
		goto HD_INFO_ERROR;
        }

	/* Offset by 1MB from end of partition */
	secoffset += hd_info->nr_sects - (1 * 1024 * 1024 /512);

	/* Make sure partition is sane size-wise */

	if(hd_info->nr_sects < secoffset){
	    goto HD_INFO_ERROR;
        }
	if(hd_info->nr_sects - secoffset < ((size + 511)/512)) {
	    goto HD_INFO_ERROR;
	}
	
	if(initdrive) {
                /* Issue software reset, disable ide interrupts */
		if(pio_reset(ap) < 0) { 
		    goto HD_INFO_ERROR;
		}
	
                initdrive=0;
	}

	tsector = hd_info->start_sect + secoffset;

        written_sect = pio_write_buffer(dev, ap, tsector, buf, size, csum);

	scsi_disk_put(sdkp);
	/* release hd_info */
    disk_put_part(hd_info);
	return written_sect;

HD_INFO_ERROR:
    /* release hd_info */
    disk_put_part(hd_info);
    return -ENODEV;
}
Пример #2
0
int pio_write_corefile(int offset) {
	/*
	 * The original idea here is to write to the "alternate
	 * application partition".  This has some problems though,
	 * spec. with developer boxes.  For now, we're going to
	 * assume this won't be called from a dev build.  (This is so
	 * broken it bothers me, we could write it to swap -32M -1M)
	 *
	 * The second broken thing here is we don't account for
	 * actual size of the memory of the box in question.  We
	 * assume it's 32Meg.  This is somewhat easily overcome by
	 * just checking the config variables.  However, I'm loathe
	 * to do that at this point since having variable size input
	 * just risks adding a new bug to the system.  (Something I don't
	 * want to do at this point in the release cycle)
	 *
	 * This is a *very basic* implementation of what we want to do.
	 * It starts at 0x80000000, goes for 32MB writing out to alternate
	 * application at either "offset 0", or "offset 1".  Offset 0 is
	 * at the beginning of the partition.  Offset 1 is 32MB into the
	 * partition.  (ah, now you see why I don't want to deal with
	 * variable sizes)
	 *
	 * Cache flushing is not required as we're doing it PIO, which just
	 * pulls from cache.  Of course, we're taking the kernel centric
	 * as opposed to hardware centric view of memory.  This is reasonable
	 * because really, the core is just a bunch of kernel memory
	 * structures for the most part.
	 * 
	 */
	struct block_device *bdev;
	struct gendisk *gp;
	struct scsi_disk *sdkp;
	struct scsi_device *sdev;
	struct ata_port *ap;
	struct ata_device *dev;
	
	int altpartition;
	unsigned long secoffset = (CORE_SIZE / 512) * offset;
	u32 csum; /* Currently unused */
	static int core_written = 0;

	/* Only 0 or 1 are valid offset values */
	if(!(offset == 0 || offset == 1))
		return -EINVAL;

	/* If the root is sda4, then altap is sda7 and vice-versa */
	if(ROOT_DEV == MKDEV(SCSI_DISK0_MAJOR, 4))
		altpartition = 7;
	else if(ROOT_DEV == MKDEV(SCSI_DISK0_MAJOR, 7))
		altpartition = 4;
	else
		return -ENODEV;

        if( (bdev = bdget(MKDEV(SCSI_DISK0_MAJOR, 0))) != NULL )
        { 
                if( (gp = bdev->bd_disk) != NULL){
                        if ((sdkp = scsi_disk_get(gp)) == NULL){
                                return -ENXIO;
                        }
                }
                else{
                        return -ENODEV;
                }
        }
        else{
                return -ENODEV;
        }

        if((sdev = scsi_dev_get(sdkp)) == NULL)
        {
                return -ENXIO;
        }

        ap = ata_shost_to_port(sdev->host);
	dev = ata_scsi_find_dev(ap, sdev);	  	   

        if( ap == NULL || dev == NULL ){
                return -ENXIO;
        }
        
	if(core_written != 0) {
		printk("Core already written\n");
		return -EINVAL;
	}
	
	core_written = 1;
	
	/* Partition must be at least twice a CORE */
	/* disk_get_part() increments ref count so need to release */
	struct hd_struct *hd_info = disk_get_part(gp, altpartition);
	if(hd_info->nr_sects < ((2 * CORE_SIZE) / 512)) {
	    /* release hd_info */
	    disk_put_part(hd_info);
		return -ENODEV;
	}
	
	if(initdrive) {
                /* Issue software reset, disable ide interrupts */
		if(pio_reset(ap) < 0) {
		    /* release hd_info */
		    disk_put_part(hd_info);
			return -ENODEV;
		}
		initdrive=0;
	}

	secoffset += hd_info->start_sect;

	/* release hd_info */
	disk_put_part(hd_info);

	return pio_write_buffer(dev, ap, secoffset, (const u8*)CORE_START,
		       CORE_SIZE, &csum);
}
Пример #3
0
static int hd_write_pio(block_dev_t *bdev, char *buffer, size_t count, blkno_t blkno) {
	hd_t *hd;
	hdc_t *hdc;
	int sectsleft;
	int nsects;
	int n;
	int result = 0;
	char *bufp;

	if (count == 0) {
		return 0;
	}
	bufp = (char *) buffer;
	hd = (hd_t *) bdev->privdata;
	hdc = hd->hdc;
	sectsleft = count / bdev->block_size;


	while (sectsleft > 0) {
		/* Select drive */
		ide_select_drive(hd);

		/* Wait for controller ready */
		result = ide_wait(hdc, HDCS_DRDY, HDTIMEOUT_DRDY);
		if (result != 0) {
			hdc->result = -EIO;
			break;
		}

		nsects = 1;

		/* Prepare transfer */
		hdc->bufp = bufp;
		hdc->nsects = nsects;
		hdc->result = 0;
		hdc->dir = HD_XFER_WRITE;
		hdc->active = hd;

		hd_setup_transfer(hd, blkno, nsects);
		outb(hd->multsect > 1 ? HDCMD_MULTWRITE : HDCMD_WRITE,
				hdc->iobase + HDC_COMMAND);

		/* Wait for data ready */
		if (!(inb(hdc->iobase + HDC_ALT_STATUS) & HDCS_DRQ)) {
			result = ide_wait(hdc, HDCS_DRQ, HDTIMEOUT_DRQ);
			if (result != 0) {
				hdc->result = -EIO;
				break;
			}
		}

		/* Write first sector(s) */
		n = hd->multsect;
		if (n > nsects) {
			n = nsects;
		}
		while (n-- > 0) {
			pio_write_buffer(hd, hdc->bufp, bdev->block_size);
			hdc->bufp += bdev->block_size;
		}

		/* Wait until data written */
		WAITQ_WAIT(&hdc->waitq, hdc->result);

		if (hdc->result < 0) {
			break;
		}

		/* Advance to next */
		sectsleft -= nsects;
		bufp += nsects * bdev->block_size;
		blkno += nsects; /*WTF?*/
	}

	/* Cleanup */
	hdc->dir = HD_XFER_IDLE;
	hdc->active = NULL;

	/*
	 * FIXME This assignment crashes writing, because
	 * hdc->result equal 1 after writing. So, it set result to 1, afterward
	 * (return result == 0 ? count : result) return 1.
	 * --Alexander
	 *
	result = hdc->result;
	*/

	return result == 0 ? count : result;
}