===== drivers/block/elevator.c 1.29 vs edited ===== --- 1.29/drivers/block/elevator.c Fri Oct 4 15:58:57 2002 +++ edited/drivers/block/elevator.c Sun Oct 20 16:23:10 2002 @@ -272,13 +272,27 @@ e->elevator_merge_req_fn(q, rq, next); } -/* - * add_request and next_request are required to be supported, naturally - */ -void __elv_add_request(request_queue_t *q, struct request *rq, - struct list_head *insert_here) +void __elv_add_request(request_queue_t *q, struct request *rq, int at_end, + int plug) { - q->elevator.elevator_add_req_fn(q, rq, insert_here); + struct list_head *insert = &q->queue_head; + + if (at_end) + insert = insert->prev; + if (plug) + blk_plug_device(q); + + q->elevator.elevator_add_req_fn(q, rq, insert); +} + +void elv_add_request(request_queue_t *q, struct request *rq, int at_end, + int plug) +{ + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __elv_add_request(q, rq, at_end, plug); + spin_unlock_irqrestore(q->queue_lock, flags); } static inline struct request *__elv_next_request(request_queue_t *q) @@ -357,6 +371,7 @@ EXPORT_SYMBOL(elevator_noop); +EXPORT_SYMBOL(elv_add_request); EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_next_request); EXPORT_SYMBOL(elv_remove_request); ===== drivers/block/ll_rw_blk.c 1.123 vs edited ===== --- 1.123/drivers/block/ll_rw_blk.c Fri Oct 18 19:41:37 2002 +++ edited/drivers/block/ll_rw_blk.c Sun Oct 20 15:38:58 2002 @@ -639,7 +639,7 @@ blk_queue_end_tag(q, rq); rq->flags &= ~REQ_STARTED; - elv_add_request(q, rq, 0); + __elv_add_request(q, rq, 0, 0); } } @@ -662,7 +662,7 @@ { int bit; - printk("%s: dev %02x:%02x: ", msg, major(rq->rq_dev), minor(rq->rq_dev)); + printk("%s: dev %02x:%02x: flags = ", msg, major(rq->rq_dev), minor(rq->rq_dev)); bit = 0; do { if (rq->flags & (1 << bit)) @@ -670,10 +670,17 @@ bit++; } while (bit < __REQ_NR_BITS); - printk("sector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector, + printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); - printk("bio %p, biotail %p\n", rq->bio, rq->biotail); + printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len); + + if (rq->flags & REQ_BLOCK_PC) { + printk("cdb: "); + for (bit = 0; bit < sizeof(rq->cmd); bit++) + printk("%02x ", rq->cmd[bit]); + printk("\n"); + } } void blk_recount_segments(request_queue_t *q, struct bio *bio) @@ -1265,6 +1272,7 @@ if (!list_empty(&rl->free)) { rq = blkdev_free_rq(&rl->free); list_del(&rq->queuelist); + rq->ref_count = 1; rl->count--; if (rl->count < queue_congestion_on_threshold()) set_queue_congested(q, rw); @@ -1386,7 +1394,7 @@ if (blk_rq_tagged(rq)) blk_queue_end_tag(q, rq); - _elv_add_request(q, rq, !at_head, 0); + __elv_add_request(q, rq, !at_head, 0); q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -1466,7 +1474,7 @@ * elevator indicated where it wants this request to be * inserted at elevator_merge time */ - __elv_add_request(q, req, insert_here); + __elv_add_request_pos(q, req, insert_here); } /* @@ -1477,6 +1485,9 @@ struct request_list *rl = req->rl; request_queue_t *q = req->q; + if (unlikely(--req->ref_count)) + return; + req->rq_status = RQ_INACTIVE; req->q = NULL; req->rl = NULL; @@ -2088,6 +2099,8 @@ init_waitqueue_head(&congestion_states[i].wqh); atomic_set(&congestion_states[i].nr_congested_queues, 0); } + + printk("block: sizeof(struct request) = %d\n", sizeof(struct request)); return 0; }; ===== drivers/block/scsi_ioctl.c 1.12 vs edited ===== --- 1.12/drivers/block/scsi_ioctl.c Tue Oct 15 20:50:18 2002 +++ edited/drivers/block/scsi_ioctl.c Sun Oct 20 18:30:39 2002 @@ -29,11 +29,14 @@ #include #include #include +#include #include #include +#define BLK_DEFAULT_TIMEOUT (60 * HZ) + int blk_do_rq(request_queue_t *q, struct request *rq) { DECLARE_COMPLETION(wait); @@ -41,13 +44,11 @@ rq->flags |= REQ_NOMERGE; rq->waiting = &wait; - elv_add_request(q, rq, 1); + rq->ref_count++; + elv_add_request(q, rq, 1, 1); generic_unplug_device(q); wait_for_completion(&wait); - /* - * for now, never retry anything - */ if (rq->errors) err = -EIO; @@ -74,42 +75,51 @@ static int sg_get_timeout(request_queue_t *q) { - return HZ; + return q->sg_timeout; } static int sg_set_timeout(request_queue_t *q, int *p) { - int timeout; - int error = get_user(timeout, p); - return error; -} + int timeout, err = get_user(timeout, p); + + if (!err) + q->sg_timeout = timeout; -static int reserved_size = 0; + return err; +} static int sg_get_reserved_size(request_queue_t *q, int *p) { - return put_user(reserved_size, p); + return put_user(q->sg_reserved_size, p); } static int sg_set_reserved_size(request_queue_t *q, int *p) { - int size; - int error = get_user(size, p); - if (!error) - reserved_size = size; - return error; + int size, err = get_user(size, p); + + if (!err) + q->sg_reserved_size = size; + + return err; } +/* + * will always return that we are ATAPI even for a real SCSI drive, I'm not + * so sure this is worth doing anything about (why would you care??) + */ static int sg_emulated_host(request_queue_t *q, int *p) { return put_user(1, p); } -static int sg_io(request_queue_t *q, struct sg_io_hdr *uptr) +static int sg_io(request_queue_t *q, struct block_device *bdev, + struct sg_io_hdr *uptr) { - int err; + unsigned long uaddr, start_time; + int err, reading, writing; struct sg_io_hdr hdr; struct request *rq; + struct bio *bio; void *buffer; if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr))) @@ -117,47 +127,131 @@ if (copy_from_user(&hdr, uptr, sizeof(*uptr))) return -EFAULT; - if ( hdr.cmd_len > sizeof(rq->cmd) ) + if (hdr.cmd_len > sizeof(rq->cmd)) + return -EINVAL; + if (!access_ok(VERIFY_READ, hdr.cmdp, hdr.cmd_len)) + return -EFAULT; + + if (hdr.dxfer_len > 65536) return -EINVAL; + /* + * we'll do that later + */ + if (hdr.iovec_count) + return -EOPNOTSUPP; + + reading = writing = 0; buffer = NULL; + bio = NULL; if (hdr.dxfer_len) { unsigned int bytes = (hdr.dxfer_len + 511) & ~511; switch (hdr.dxfer_direction) { default: return -EINVAL; + case SG_DXFER_TO_FROM_DEV: + reading = 1; + /* fall through */ case SG_DXFER_TO_DEV: + writing = 1; + break; case SG_DXFER_FROM_DEV: - case SG_DXFER_TO_FROM_DEV: + reading = 1; break; } - buffer = kmalloc(bytes, GFP_USER); - if (!buffer) - return -ENOMEM; - if (hdr.dxfer_direction == SG_DXFER_TO_DEV || - hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV) - copy_from_user(buffer, hdr.dxferp, hdr.dxfer_len); + + uaddr = (unsigned long) hdr.dxferp; + if (writing && !access_ok(VERIFY_WRITE, uaddr, bytes)) + return -EFAULT; + if (reading && !access_ok(VERIFY_READ, uaddr, bytes)) + return -EFAULT; + + /* + * first try to map it into a bio. reading from device will + * be a write to vm. + */ + bio = bio_map_user(bdev, uaddr, hdr.dxfer_len, reading); + if (bio && (bio->bi_size < hdr.dxfer_len)) { + bio_endio(bio, bio->bi_size, 0); + bio = NULL; + } + + /* + * if bio setup failed, fall back to slow approach + */ + if (!bio) { + buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER); + if (!buffer) + return -ENOMEM; + + if (writing) + copy_from_user(buffer,hdr.dxferp,hdr.dxfer_len); + else + memset(buffer, 0, hdr.dxfer_len); + } } rq = blk_get_request(q, WRITE, __GFP_WAIT); - rq->timeout = 60*HZ; + rq->bio = rq->biotail = bio; rq->data = buffer; + + if (bio) { + if (writing) + bio->bi_rw |= (1 << BIO_RW); + + rq->buffer = bio_data(bio); + rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); + rq->current_nr_sectors = bio_cur_sectors(bio); + rq->hard_cur_sectors = rq->current_nr_sectors; + rq->nr_phys_segments = bio_phys_segments(q, bio); + rq->nr_hw_segments = bio_hw_segments(q, bio); + } + + rq->rq_dev = to_kdev_t(bdev->bd_dev); + rq->rq_disk = bdev->bd_disk; + + rq->timeout = hdr.timeout; + if (!rq->timeout) + rq->timeout = q->sg_timeout; + if (!rq->timeout) + rq->timeout = BLK_DEFAULT_TIMEOUT; + rq->data_len = hdr.dxfer_len; - rq->flags = REQ_BLOCK_PC; + rq->flags |= REQ_BLOCK_PC; + if (writing) + rq->flags |= REQ_RW; + memset(rq->cmd, 0, sizeof(rq->cmd)); copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len); + + start_time = jiffies; + + /* + * return -EIO if we didn't transfer all data, caller can look at + * residual count to find out how much did succeed + */ err = blk_do_rq(q, rq); + if (rq->data_len > 0) + err = -EIO; + + hdr.resid = rq->data_len; + hdr.status = rq->errors; + hdr.duration = (jiffies - start_time) * 1000 / HZ; + spin_lock_irq(q->queue_lock); blk_put_request(rq); + spin_unlock_irq(q->queue_lock); copy_to_user(uptr, &hdr, sizeof(*uptr)); + if (buffer) { - if (hdr.dxfer_direction == SG_DXFER_FROM_DEV || - hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV) + if (reading) copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len); + kfree(buffer); } + return err; } @@ -189,7 +283,7 @@ case SG_EMULATED_HOST: return sg_emulated_host(q, (int *) arg); case SG_IO: - return sg_io(q, (struct sg_io_hdr *) arg); + return sg_io(q, bdev, (struct sg_io_hdr *) arg); case CDROMCLOSETRAY: close = 1; case CDROMEJECT: @@ -197,7 +291,7 @@ rq->flags = REQ_BLOCK_PC; rq->data = NULL; rq->data_len = 0; - rq->timeout = 60*HZ; + rq->timeout = BLK_DEFAULT_TIMEOUT; memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); ===== drivers/ide/ide-cd.c 1.27 vs edited ===== --- 1.27/drivers/ide/ide-cd.c Fri Oct 18 20:02:55 2002 +++ edited/drivers/ide/ide-cd.c Sun Oct 20 18:35:21 2002 @@ -608,7 +608,7 @@ if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ - if ((rq->flags & REQ_DRIVE_CMD) || (rq->flags & REQ_DRIVE_TASK)) { + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; @@ -635,15 +635,21 @@ return ide_stopped; } -static void cdrom_end_request (ide_drive_t *drive, int uptodate) +/* Handle differences between SCSI and ATAPI packet commands */ +static void post_transform_command(struct request *); + +static int cdrom_end_request (ide_drive_t *drive, int uptodate) { struct request *rq = HWGROUP(drive)->rq; if ((rq->flags & REQ_SENSE) && uptodate) { - /* For REQ_SENSE, "rq->buffer" points to the original failed request */ - struct request *failed = (struct request *) rq->buffer; + /* + * For REQ_SENSE, "rq->buffer" points to the original failed + * request + */ + struct request *failed = (struct request *) rq->buffer; struct cdrom_info *info = drive->driver_data; - void * sense = &info->sense_data; + void *sense = &info->sense_data; if (failed && failed->sense) sense = failed->sense; @@ -651,15 +657,17 @@ cdrom_analyze_sense_data(drive, failed, sense); } - if (blk_fs_request(rq) && !rq->current_nr_sectors) + if (!rq->current_nr_sectors && blk_fs_request(rq)) uptodate = 1; - ide_end_request(drive, uptodate, rq->hard_cur_sectors); -} + /* + * Fix up any SCSI command differences + */ + if (uptodate) + post_transform_command(rq); -/* Handle differences between SCSI and ATAPI packet commands */ -static int pre_transform_command(struct request *); -static void post_transform_command(struct request *); + return ide_end_request(drive, uptodate, rq->hard_cur_sectors); +} /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ @@ -672,7 +680,7 @@ /* Check for errors. */ *stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG); - if (OK_STAT (stat, good_stat, BAD_R_STAT)) + if (OK_STAT(stat, good_stat, BAD_R_STAT)) return 0; /* Get the IDE error register. */ @@ -699,9 +707,8 @@ /* All other functions, except for READ. */ struct completion *wait = NULL; - /* Fix up any SCSI command differences.. */ if (rq->flags & REQ_BLOCK_PC) - post_transform_command(rq); + rq->errors = sense_key; /* Check for tray open. */ if (sense_key == NOT_READY) { @@ -779,8 +786,10 @@ queue a request sense command. */ if ((stat & ERR_STAT) != 0) cdrom_queue_request_sense(drive, NULL, NULL, NULL); - } else - blk_dump_rq_flags(rq, "ide-cd bad flags"); + } else { + blk_dump_rq_flags(rq, "ide-cd: bad rq"); + cdrom_end_request(drive, 0); + } /* Retry, or handle the next request. */ *startstop = ide_stopped; @@ -848,7 +857,7 @@ HWIF(drive)->OUTB(xferlen >> 8 , IDE_BCOUNTH_REG); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); - + if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { if (HWGROUP(drive)->handler != NULL) BUG(); @@ -876,9 +885,6 @@ struct request *rq, ide_handler_t *handler) { - unsigned char *cmd_buf = rq->cmd; - int cmd_len = sizeof(rq->cmd); - unsigned int timeout = rq->timeout; struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; @@ -901,10 +907,10 @@ BUG(); /* Arm the interrupt handler. */ - ide_set_handler(drive, handler, timeout, cdrom_timer_expiry); + ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry); /* Send the command to the device. */ - HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len); + HWIF(drive)->atapi_output_bytes(drive, rq->cmd, sizeof(rq->cmd)); /* Start the DMA if need be */ if (info->dma) @@ -1016,7 +1022,9 @@ struct request *rq = HWGROUP(drive)->rq; - /* Check for errors. */ + /* + * handle dma case + */ if (dma) { info->dma = 0; if ((dma_error = HWIF(drive)->ide_dma_end(drive))) @@ -1025,15 +1033,20 @@ if (cdrom_decode_status (&startstop, drive, 0, &stat)) return startstop; - + if (dma) { if (!dma_error) { ide_end_request(drive, 1, rq->nr_sectors); + rq->data_len -= rq->nr_sectors << 9; return ide_stopped; } else return DRIVER(drive)->error(drive, "dma error", stat); } + /* + * below is the pio data handling + */ + /* Read the interrupt reason and the transfer length. */ ireason = HWIF(drive)->INB(IDE_IREASON_REG); lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG); @@ -1080,7 +1093,7 @@ /* First, figure out if we need to bit-bucket any of the leading sectors. */ - nskip = MIN((int)(rq->current_nr_sectors - bio_sectors(rq->bio)), sectors_to_transfer); + nskip = MIN((int)(rq->current_nr_sectors - bio_cur_sectors(rq->bio)), sectors_to_transfer); while (nskip > 0) { /* We need to throw away a sector. */ @@ -1107,6 +1120,9 @@ cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); sectors_to_transfer = 0; } else { + if (rq->bio) + rq->buffer = bio_data(rq->bio); + /* Transfer data to the buffers. Figure out how many sectors we can transfer to the current buffer. */ @@ -1121,6 +1137,7 @@ --rq->nr_sectors; --rq->current_nr_sectors; ++rq->sector; + --rq->data_len; --this_transfer; --sectors_to_transfer; } @@ -1180,7 +1197,7 @@ represent the number of sectors to skip at the start of a transfer will fail. I think that this will never happen, but let's be paranoid and check. */ - if (rq->current_nr_sectors < bio_sectors(rq->bio) && + if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) && (rq->sector % SECTORS_PER_FRAME) != 0) { printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", drive->name, (long)rq->sector); @@ -1218,7 +1235,7 @@ nskip = (sector % SECTORS_PER_FRAME); if (nskip > 0) { /* Sanity check... */ - if (rq->current_nr_sectors != bio_sectors(rq->bio) && + if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) && (rq->sector % CD_FRAMESIZE != 0)) { printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n", drive->name, rq->current_nr_sectors); @@ -1318,7 +1335,7 @@ rq->nr_sectors += n; rq->sector -= n; } - rq->hard_cur_sectors = rq->current_nr_sectors = bio_sectors(rq->bio); + rq->hard_cur_sectors = rq->current_nr_sectors = bio_cur_sectors(rq->bio); rq->hard_nr_sectors = rq->nr_sectors; rq->hard_sector = rq->sector; rq->q->prep_rq_fn(rq->q, rq); @@ -1619,7 +1636,7 @@ printk("ide-cd: write_intr decode_status bad\n"); return startstop; } - + /* * using dma, transfer is complete now */ @@ -1627,6 +1644,7 @@ if (dma_error) return DRIVER(drive)->error(drive, "dma error", stat); + rq->data_len -= rq->nr_sectors << 9; ide_end_request(drive, 1, rq->nr_sectors); return ide_stopped; } @@ -1671,6 +1689,9 @@ break; } + if (rq->bio) + rq->buffer = bio_data(rq->bio); + /* * Figure out how many sectors we can transfer */ @@ -1682,6 +1703,7 @@ --rq->nr_sectors; --rq->current_nr_sectors; ++rq->sector; + --rq->data_len; --this_transfer; --sectors_to_transfer; } @@ -1748,56 +1770,88 @@ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); } -/* - * Most of the SCSI commands are supported directly by ATAPI devices. - * This transform handles the few exceptions. - */ -static int pre_transform_command(struct request *req) +static void post_transform_command(struct request *req) { + char *ibuf = req->buffer; u8 *c = req->cmd; - /* Transform 6-byte read/write commands to the 10-byte version. */ - if (c[0] == READ_6 || c[0] == WRITE_6) { - c[8] = c[4]; - c[5] = c[3]; - c[4] = c[2]; - c[3] = c[1] & 0x1f; - c[2] = 0; - c[1] &= 0xe0; - c[0] += (READ_10 - READ_6); - return 0; + + if (!blk_pc_request(req)) + return; + + /* + * set ansi-revision and response data as atapi + */ + if (c[0] == GPCMD_INQUIRY) { + ibuf[2] |= 2; + ibuf[3] = (ibuf[3] & 0xf0) | 2; + return; } - /* These also need fixup, not done yet */ - if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) - return -EINVAL; + /* + * command was transformed MODE_SELECT_6 + */ + if (c[0] == GPCMD_MODE_SENSE_10 && req->special) { + int length = (c[7] << 8) | c[8]; + char *obuf = req->special; - return 0; + obuf[0] = ibuf[1]; + obuf[1] = ibuf[2]; + obuf[2] = ibuf[3]; + obuf[3] = ibuf[7]; + + memcpy(obuf + 4, ibuf + 8, length - 8); + + kfree(ibuf); + req->special = NULL; + req->data = obuf; + } } -static void post_transform_command(struct request *req) +static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive) { + struct cdrom_info *info = drive->driver_data; + struct request *rq = HWGROUP(drive)->rq; + ide_handler_t *handler; + + if (!rq->timeout) + rq->timeout = WAIT_CMD; + + if (info->cmd == READ) + handler = cdrom_read_intr; + else + handler = cdrom_write_intr; + + return cdrom_transfer_packet_command(drive, rq, handler); } static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) { - ide_startstop_t startstop; - struct cdrom_info *info; - - if (pre_transform_command(rq) < 0) { - cdrom_end_request(drive, 0); - return ide_stopped; - } + struct cdrom_info *info = drive->driver_data; + ide_handler_t *handler; rq->flags |= REQ_QUIET; + rq->buffer = rq->data; - info = drive->driver_data; info->dma = 0; info->cmd = 0; + handler = cdrom_do_pc_continuation; - /* Start sending the command to the drive. */ - startstop = cdrom_start_packet_command(drive, rq->data_len, cdrom_do_pc_continuation); + /* + * sg request + */ + if (rq->bio) { + if (rq->data_len & 511) { + printk("%s: block pc not aligned, len=%d\n", drive->name, rq->data_len); + cdrom_end_request(drive, 0); + return ide_stopped; + } + info->dma = drive->using_dma; + info->cmd = rq_data_dir(rq); + handler = cdrom_do_newpc_cont; + } - return startstop; + /* Start sending the command to the drive. */ + return cdrom_start_packet_command(drive, rq->data_len, handler); } /**************************************************************************** @@ -2314,7 +2368,7 @@ req.sense = cgc->sense; cgc->stat = cdrom_queue_packet_command(drive, &req); if (!cgc->stat) - cgc->buflen -= req.data_len; + cgc->buflen = req.data_len; return cgc->stat; } @@ -2828,15 +2882,12 @@ /* * standard prep_rq_fn that builds 10 byte cmds */ -static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq) +static int ide_cdrom_prep_fs(request_queue_t *q, struct request *rq) { int hard_sect = queue_hardsect_size(q); long block = (long)rq->hard_sector / (hard_sect >> 9); unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); - if (!(rq->flags & REQ_CMD)) - return 0; - BUG_ON(sizeof(rq->hard_sector) > 4 && (rq->hard_sector >> 32)); if (rq->hard_nr_sectors != rq->nr_sectors) { @@ -2863,6 +2914,91 @@ */ rq->cmd[7] = (blocks >> 8) & 0xff; rq->cmd[8] = blocks & 0xff; + return 0; +} + +/* + * Most of the SCSI commands are supported directly by ATAPI devices. + * This transform handles the few exceptions. + */ +static int ide_cdrom_prep_pc(struct request *rq) +{ + u8 *c = rq->cmd; + + /* + * Transform 6-byte read/write commands to the 10-byte version + */ + if (c[0] == READ_6 || c[0] == WRITE_6) { + c[8] = c[4]; + c[5] = c[3]; + c[4] = c[2]; + c[3] = c[1] & 0x1f; + c[2] = 0; + c[1] &= 0xe0; + c[0] += (READ_10 - READ_6); + return 0; + } + + if (!rq->data_len || !rq->data) + return 0; + + if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { + char *obuf = rq->data; + char old_cdb[6]; + char *buffer; + int new_len; + + if (rq->bio) + return -EINVAL; + + /* + * 10-byte variant needs a bit more room + */ + buffer = kmalloc(rq->data_len + 4, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + /* + * transform the cdb + */ + memcpy(old_cdb, c, sizeof(old_cdb)); + memset(buffer, 0, rq->data_len + 4); + memset(rq->cmd, 0, sizeof(rq->cmd)); + c[0] = old_cdb[0] | 0x40; + c[1] = old_cdb[1]; + c[2] = old_cdb[2]; + new_len = old_cdb[4] + 4; + c[8] = new_len & 0xff; + c[7] = (new_len >> 8) & 0xff; + c[9] = old_cdb[5]; + + if (c[0] == GPCMD_MODE_SELECT_10) { + buffer[1] = obuf[0]; + buffer[2] = obuf[1]; + buffer[3] = obuf[2]; + buffer[7] = obuf[3]; + memcpy(buffer + 8, obuf + 4, rq->data_len - 4); + } + + /* + * keep old buffer in ->special, set the new one and + * adjust transfer length + */ + rq->special = rq->data; + rq->buffer = buffer; + rq->data = buffer; + rq->data_len += 4; + } + + return 0; +} + +static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq) +{ + if (rq->flags & REQ_CMD) + return ide_cdrom_prep_fs(q, rq); + else if (rq->flags & REQ_BLOCK_PC) + return ide_cdrom_prep_pc(rq); return 0; } @@ -2880,7 +3016,7 @@ set_device_ro(mk_kdev(drive->disk->major, drive->disk->first_minor), 1); blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE); - blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build); + blk_queue_prep_rq(&drive->queue, ide_cdrom_prep_fn); drive->special.all = 0; drive->ready_stat = 0; ===== drivers/md/linear.c 1.20 vs edited ===== --- 1.20/drivers/md/linear.c Wed Oct 16 06:49:22 2002 +++ edited/drivers/md/linear.c Fri Oct 18 20:28:57 2002 @@ -52,8 +52,7 @@ * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * - * Return 1 if the merge is not permitted (because the - * result would cross a device boundary), 0 otherwise. + * FIXME: return amount we can take at this offset, not a bool */ static int linear_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec) { @@ -64,7 +63,10 @@ dev1 = which_dev(mddev, bio->bi_sector + ((bio->bi_size + biovec->bv_len - 1) >> 9)); - return dev0 != dev1; + if (dev0 == dev1) + return biovec->bv_len; + + return 0; } static int linear_run (mddev_t *mddev) ===== drivers/md/raid0.c 1.18 vs edited ===== --- 1.18/drivers/md/raid0.c Tue Oct 15 12:03:07 2002 +++ edited/drivers/md/raid0.c Fri Oct 18 20:28:57 2002 @@ -168,8 +168,7 @@ * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * - * Return 1 if the merge is not permitted (because the - * result would cross a chunk boundary), 0 otherwise. + * Return amount of bytes we can accept at this offset */ static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec) { @@ -182,7 +181,7 @@ block = bio->bi_sector >> 1; bio_sz = (bio->bi_size + biovec->bv_len) >> 10; - return chunk_size < ((block & (chunk_size - 1)) + bio_sz); + return chunk_size - ((block & (chunk_size - 1)) + bio_sz); } static int raid0_run (mddev_t *mddev) ===== drivers/scsi/scsi_lib.c 1.35 vs edited ===== --- 1.35/drivers/scsi/scsi_lib.c Fri Oct 18 21:19:51 2002 +++ edited/drivers/scsi/scsi_lib.c Sun Oct 20 16:18:15 2002 @@ -240,7 +240,7 @@ SCpnt->request->special = (void *) SCpnt; if(blk_rq_tagged(SCpnt->request)) blk_queue_end_tag(q, SCpnt->request); - _elv_add_request(q, SCpnt->request, 0, 0); + __elv_add_request(q, SCpnt->request, 0, 0); } /* @@ -514,6 +514,12 @@ } } + if (blk_pc_request(req)) { + req->errors = result; + if (!result) + req->data_len -= SCpnt->bufflen; + } + /* * Zero these out. They now point to freed memory, and it is * dangerous to hang onto the pointers. @@ -527,7 +533,7 @@ * Next deal with any sectors which we were able to correctly * handle. */ - if (good_sectors > 0) { + if (good_sectors >= 0) { SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d sectors done.\n", req->nr_sectors, good_sectors)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg)); @@ -951,7 +957,7 @@ SCpnt->request->flags |= REQ_SPECIAL; if(blk_rq_tagged(SCpnt->request)) blk_queue_end_tag(q, SCpnt->request); - _elv_add_request(q, SCpnt->request, 0, 0); + __elv_add_request(q, SCpnt->request, 0, 0); break; } ===== drivers/scsi/scsi_merge.c 1.24 vs edited ===== --- 1.24/drivers/scsi/scsi_merge.c Fri Oct 18 21:19:51 2002 +++ edited/drivers/scsi/scsi_merge.c Sat Oct 19 12:09:09 2002 @@ -62,15 +62,9 @@ int count, gfp_mask; /* - * non-sg block request. FIXME: check bouncing for isa hosts! + * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer */ if ((req->flags & REQ_BLOCK_PC) && !req->bio) { - /* - * FIXME: isa bouncing - */ - if (SCpnt->host->unchecked_isa_dma) - goto fail; - SCpnt->request_bufflen = req->data_len; SCpnt->request_buffer = req->data; req->buffer = req->data; @@ -123,7 +117,6 @@ /* * kill it. there should be no leftover blocks in this request */ -fail: SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors); BUG_ON(SCpnt); return 0; ===== drivers/scsi/sd.c 1.73 vs edited ===== --- 1.73/drivers/scsi/sd.c Fri Oct 18 22:32:54 2002 +++ edited/drivers/scsi/sd.c Sat Oct 19 16:52:55 2002 @@ -308,6 +308,8 @@ if (rq->timeout) timeout = rq->timeout; + SCpnt->transfersize = rq->data_len; + SCpnt->underflow = rq->data_len; goto queue; } @@ -431,10 +433,10 @@ * host adapter, it's safe to assume that we can at least transfer * this many bytes between each connect / disconnect. */ -queue: SCpnt->transfersize = sdp->sector_size; SCpnt->underflow = this_count << 9; +queue: SCpnt->allowed = MAX_RETRIES; SCpnt->timeout_per_command = timeout; ===== drivers/scsi/sr.c 1.56 vs edited ===== --- 1.56/drivers/scsi/sr.c Sat Oct 19 00:03:16 2002 +++ edited/drivers/scsi/sr.c Sat Oct 19 16:53:32 2002 @@ -287,6 +287,8 @@ if (rq->timeout) timeout = rq->timeout; + SCpnt->transfersize = rq->data_len; + SCpnt->underflow = rq->data_len; goto queue; } @@ -360,10 +362,10 @@ * host adapter, it's safe to assume that we can at least transfer * this many bytes between each connect / disconnect. */ -queue: SCpnt->transfersize = cd->device->sector_size; SCpnt->underflow = this_count << 9; +queue: SCpnt->allowed = MAX_RETRIES; SCpnt->timeout_per_command = timeout; ===== fs/bio.c 1.31 vs edited ===== --- 1.31/fs/bio.c Sat Oct 19 01:14:39 2002 +++ edited/fs/bio.c Sat Oct 19 12:06:29 2002 @@ -354,7 +354,7 @@ request_queue_t *q = bdev_get_queue(bdev); int nr_pages; - nr_pages = q->max_sectors >> (PAGE_SHIFT - 9); + nr_pages = ((q->max_sectors << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (nr_pages > q->max_phys_segments) nr_pages = q->max_phys_segments; if (nr_pages > q->max_hw_segments) @@ -385,13 +385,13 @@ * cloned bio must not modify vec list */ if (unlikely(bio_flagged(bio, BIO_CLONED))) - return 1; + return 0; if (bio->bi_vcnt >= bio->bi_max_vecs) - return 1; + return 0; if (((bio->bi_size + len) >> 9) > q->max_sectors) - return 1; + return 0; /* * we might loose a segment or two here, but rather that than @@ -404,7 +404,7 @@ if (fail_segments) { if (retried_segments) - return 1; + return 0; bio->bi_flags &= ~(1 << BIO_SEG_VALID); retried_segments = 1; @@ -425,21 +425,129 @@ * depending on offset), it can specify a merge_bvec_fn in the * queue to get further control */ - if (q->merge_bvec_fn && q->merge_bvec_fn(q, bio, bvec)) { - bvec->bv_page = NULL; - bvec->bv_len = 0; - bvec->bv_offset = 0; - return 1; + if (q->merge_bvec_fn) { + /* + * merge_bvec_fn() returns number of bytes it can accept + * at this offset + */ + if (q->merge_bvec_fn(q, bio, bvec) < len) { + bvec->bv_page = NULL; + bvec->bv_len = 0; + bvec->bv_offset = 0; + return 0; + } } bio->bi_vcnt++; bio->bi_phys_segments++; bio->bi_hw_segments++; bio->bi_size += len; + return len; +} + +static int bio_user_end_io(struct bio *bio, unsigned int bytes_done, int error) +{ + struct bio_vec *bvec; + int i; + + if (bio->bi_size) + return 1; + + bio_for_each_segment(bvec, bio, i) + page_cache_release(bvec->bv_page); + + bio_put(bio); return 0; } /** + * bio_map_user - map user address into bio + * @bdev: destination block device + * @uaddr: start of user address + * @len: length in bytes + * @write_to_vm: bool indicating writing to pages or not + * + * Map the user space address into a bio suitable for io to a block + * device. Caller should check the size of the returned bio, we might + * not have mapped the entire range specified. + */ +struct bio *bio_map_user(struct block_device *bdev, unsigned long uaddr, + unsigned int len, int write_to_vm) +{ + unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int nr_pages = end - start; + int ret, offset, i, align_mask; + struct page **pages; + struct bio *bio; + + /* + * transfer and buffer must be aligned to at least hardsector + * size for now, in the future we can relax this restriction + */ + align_mask = bdev_hardsect_size(bdev) - 1; + if ((uaddr & align_mask) || (len & align_mask)) + return NULL; + + bio = bio_alloc(GFP_KERNEL, nr_pages); + if (!bio) + return NULL; + + pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); + if (!pages) + goto out; + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, uaddr, nr_pages, + write_to_vm, 0, pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret < nr_pages) + goto out; + + bio->bi_bdev = bdev; + + offset = uaddr & ~PAGE_MASK; + for (i = 0; i < nr_pages; i++) { + unsigned int bytes = PAGE_SIZE - offset; + + if (len <= 0) + break; + + if (bytes > len) + bytes = len; + + /* + * sorry... + */ + if (bio_add_page(bio, pages[i], bytes, offset) < bytes) + break; + + len -= bytes; + offset = 0; + } + + /* + * release the pages we didn't map into the bio, if any + */ + while (i < nr_pages) + page_cache_release(pages[i++]); + + bio->bi_end_io = bio_user_end_io; + kfree(pages); + + /* + * check if the mapped pages need bouncing for an isa host + */ + blk_queue_bounce(bdev_get_queue(bdev), &bio); + return bio; +out: + kfree(pages); + bio_put(bio); + return NULL; +} + +/** * bio_endio - end I/O on a bio * @bio: bio * @bytes_done: number of bytes completed @@ -537,7 +645,7 @@ return 0; } -module_init(init_bio); +subsys_initcall(init_bio); EXPORT_SYMBOL(bio_alloc); EXPORT_SYMBOL(bio_put); @@ -550,3 +658,4 @@ EXPORT_SYMBOL(bio_hw_segments); EXPORT_SYMBOL(bio_add_page); EXPORT_SYMBOL(bio_get_nr_vecs); +EXPORT_SYMBOL(bio_map_user); ===== fs/direct-io.c 1.14 vs edited ===== --- 1.14/fs/direct-io.c Sun Oct 13 00:45:44 2002 +++ edited/fs/direct-io.c Fri Oct 18 20:28:57 2002 @@ -417,7 +417,7 @@ /* Take a ref against the page each time it is placed into a BIO */ page_cache_get(page); - if (bio_add_page(dio->bio, page, bv_len, bv_offset)) { + if (bio_add_page(dio->bio, page, bv_len, bv_offset) < bv_len) { dio_bio_submit(dio); ret = dio_new_bio(dio, blkno); if (ret == 0) { ===== fs/mpage.c 1.25 vs edited ===== --- 1.25/fs/mpage.c Wed Oct 16 02:30:10 2002 +++ edited/fs/mpage.c Fri Oct 18 20:28:57 2002 @@ -176,6 +176,7 @@ unsigned first_hole = blocks_per_page; struct block_device *bdev = NULL; struct buffer_head bh; + int length; if (page_has_buffers(page)) goto confused; @@ -233,7 +234,8 @@ goto confused; } - if (bio_add_page(bio, page, first_hole << blkbits, 0)) { + length = first_hole << blkbits; + if (bio_add_page(bio, page, length, 0) < length) { bio = mpage_bio_submit(READ, bio); goto alloc_new; } @@ -334,6 +336,7 @@ int boundary = 0; sector_t boundary_block = 0; struct block_device *boundary_bdev = NULL; + int length; if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); @@ -467,7 +470,8 @@ try_to_free_buffers(page); } - if (bio_add_page(bio, page, first_unmapped << blkbits, 0)) { + length = first_unmapped << blkbits; + if (bio_add_page(bio, page, length, 0) < length) { bio = mpage_bio_submit(WRITE, bio); goto alloc_new; } ===== fs/xfs/pagebuf/page_buf.c 1.15 vs edited ===== --- 1.15/fs/xfs/pagebuf/page_buf.c Mon Oct 14 22:54:12 2002 +++ edited/fs/xfs/pagebuf/page_buf.c Fri Oct 18 20:28:57 2002 @@ -1448,7 +1448,7 @@ if (nbytes > size) nbytes = size; - if (bio_add_page(bio, pb->pb_pages[map_i], nbytes, offset)) + if (bio_add_page(bio, pb->pb_pages[map_i], nbytes, offset) < nbytes) break; offset = 0; ===== include/linux/bio.h 1.22 vs edited ===== --- 1.22/include/linux/bio.h Tue Oct 8 13:27:47 2002 +++ edited/include/linux/bio.h Fri Oct 18 20:28:57 2002 @@ -131,6 +131,7 @@ #define bio_page(bio) bio_iovec((bio))->bv_page #define bio_offset(bio) bio_iovec((bio))->bv_offset #define bio_sectors(bio) ((bio)->bi_size >> 9) +#define bio_cur_sectors(bio) (bio_iovec(bio)->bv_len >> 9) #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) #define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) @@ -214,6 +215,8 @@ extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); extern int bio_get_nr_vecs(struct block_device *); +extern struct bio *bio_map_user(struct block_device *, unsigned long, + unsigned int, int); #ifdef CONFIG_HIGHMEM /* ===== include/linux/blk.h 1.27 vs edited ===== --- 1.27/include/linux/blk.h Wed Jun 19 03:06:24 2002 +++ edited/include/linux/blk.h Sat Oct 19 10:59:37 2002 @@ -50,22 +50,6 @@ elv_remove_request(req->q, req); } -#define _elv_add_request_core(q, rq, where, plug) \ - do { \ - if ((plug)) \ - blk_plug_device((q)); \ - (q)->elevator.elevator_add_req_fn((q), (rq), (where)); \ - } while (0) - -#define _elv_add_request(q, rq, back, p) do { \ - if ((back)) \ - _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \ - else \ - _elv_add_request_core((q), (rq), &(q)->queue_head, (p)); \ -} while (0) - -#define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1) - #if defined(MAJOR_NR) || defined(IDE_DRIVER) #if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR) #if !defined(IDE_DRIVER) ===== include/linux/blkdev.h 1.76 vs edited ===== --- 1.76/include/linux/blkdev.h Fri Oct 18 19:50:43 2002 +++ edited/include/linux/blkdev.h Sun Oct 20 14:38:38 2002 @@ -26,6 +26,8 @@ struct list_head queuelist; /* looking for ->queue? you must _not_ * access it directly, use * blkdev_dequeue_request! */ + int ref_count; + void *elevator_private; unsigned char cmd[16]; @@ -219,6 +221,12 @@ wait_queue_head_t queue_wait; struct blk_queue_tag *queue_tags; + + /* + * sg stuff + */ + unsigned int sg_timeout; + unsigned int sg_reserved_size; }; #define RQ_INACTIVE (-1) ===== include/linux/elevator.h 1.16 vs edited ===== --- 1.16/include/linux/elevator.h Fri Oct 4 15:58:56 2002 +++ edited/include/linux/elevator.h Sat Oct 19 11:02:13 2002 @@ -40,8 +40,8 @@ /* * block elevator interface */ -extern void __elv_add_request(request_queue_t *, struct request *, - struct list_head *); +extern void elv_add_request(request_queue_t *, struct request *, int, int); +extern void __elv_add_request(request_queue_t *, struct request *, int, int); extern int elv_merge(request_queue_t *, struct list_head **, struct bio *); extern void elv_merge_requests(request_queue_t *, struct request *, struct request *); @@ -49,6 +49,9 @@ extern void elv_remove_request(request_queue_t *, struct request *); extern int elv_queue_empty(request_queue_t *); extern inline struct list_head *elv_get_sort_head(request_queue_t *, struct request *); + +#define __elv_add_request_pos(q, rq, pos) \ + (q)->elevator.elevator_add_req_fn((q), (rq), (pos)) /* * noop I/O scheduler. always merges, always inserts new request at tail