/* 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; }
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); }
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; }