📄 dasd.c
字号:
type = dasd_none; } FUNCTION_EXIT ("check_type"); return type;}static intdasd_read_characteristics (dasd_information_t * info){ int rc; int ct = 0; dev_info_t *di; dasd_type_t dt; FUNCTION_ENTRY ("read_characteristics"); if (info == NULL) { return -ENODEV; } di = &(info->info); if (di == NULL) { return -ENODEV; } dt = check_type (di); /* Some cross-checks, if the cu supports RDC */ if (MATCH (di, == 0x2835, ||1, ||1, ||1) || MATCH (di, == 0x3830, ||1, ||1, ||1) || MATCH (di, == 0x3830, ||1, ||1, ||1) || MATCH (di, == 0x3990, <=0x03, == 0x3380, <=0x0d)) { PRINT_WARN ("Device %d (%x/%x at %x/%x) supports no RDC\n", info->info.irq, di->sid_data.dev_type, di->sid_data.dev_model, di->sid_data.cu_type, di->sid_data.cu_model); return -EINVAL; } switch (dt) {#ifdef CONFIG_DASD_ECKD case dasd_eckd: ct = 64; rc = read_dev_chars (info->info.irq, (void *) &(info->rdc_data), ct); break;#endif /* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSK case dasd_mdsk: ct = 0; break;#endif /* CONFIG_DASD_MDSK */ default: INTERNAL_ERROR ("don't know dasd type %d\n", dt); } if (rc) { PRINT_WARN ("RDC resulted in rc=%d\n", rc); } FUNCTION_EXIT ("read_characteristics"); return rc;}/* How many sectors must be in a request to dequeue it ? */#define QUEUE_BLOCKS 25#define QUEUE_SECTORS (QUEUE_BLOCKS << dasd_info[di]->sizes.s2b_shift)/* How often to retry an I/O before raising an error */#define DASD_MAX_RETRIES 5static inline cqr_t *dasd_cqr_from_req (struct request *req){ cqr_t *cqr = NULL; int di; dasd_information_t *info; if (!req) { PRINT_ERR ("No request passed!"); return NULL; } di = DEVICE_NR (req->rq_dev); info = dasd_info[di]; if (!info) return NULL; /* if applicable relocate block */ if (MINOR (req->rq_dev) & ((1 << PARTN_BITS) - 1) ) { req->sector += dd_gendisk.part[MINOR(req->rq_dev)].start_sect; } /* Now check for consistency */ if (!req->nr_sectors) { PRINT_WARN ("req: %p dev: %08x sector: %ld nr_sectors: %ld bh: %p\n", req, req->rq_dev, req->sector, req->nr_sectors, req->bh); return NULL; } if (((req->sector + req->nr_sectors) >> 1) > info->sizes.kbytes) { printk (KERN_ERR PRINTK_HEADER "Requesting I/O past end of device %d\n", di); return NULL; } cqr = dasd_disciplines[info->type]->get_req_ccw (di, req); if (!cqr) { PRINT_WARN ("empty CQR generated\n"); } else { cqr->req = req; cqr->int4cqr = cqr; cqr->devindex = di;#ifdef DASD_PROFILE asm volatile ("STCK %0":"=m" (cqr->buildclk));#endif /* DASD_PROFILE */ if (atomic_compare_and_swap (CQR_STATUS_EMPTY, CQR_STATUS_FILLED, &cqr->status)) { PRINT_WARN ("cqr from req stat changed %d\n", atomic_read (&cqr->status)); } } return cqr;}intdasd_start_IO (cqr_t * cqr){ int rc = 0; int retries = DASD_SSCH_RETRIES; int di, irq; dasd_debug ((unsigned long) cqr); /* cqr */ if (!cqr) { PRINT_WARN ("(start_IO) no cqr passed\n"); return -EINVAL; } if (cqr->magic != DASD_MAGIC) { PRINT_WARN ("(start_IO) magic number mismatch\n"); return -EINVAL; } if (atomic_compare_and_swap (CQR_STATUS_QUEUED, CQR_STATUS_IN_IO, &cqr->status)) { PRINT_WARN ("start_IO: status changed %d\n", atomic_read (&cqr->status)); atomic_set (&cqr->status, CQR_STATUS_ERROR); return -EINVAL; } di = cqr->devindex; irq = dasd_info[di]->info.irq; do { asm volatile ("STCK %0":"=m" (cqr->startclk)); rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options); switch (rc) { case 0: if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) atomic_set_mask (DASD_CHANQ_BUSY, &dasd_info[di]->queue.flags); break; case -ENODEV: PRINT_WARN ("cqr %p: 0x%04x error, %d retries left\n", cqr, dasd_info[di]->info.devno, retries); break; case -EIO: PRINT_WARN ("cqr %p: 0x%04x I/O, %d retries left\n", cqr, dasd_info[di]->info.devno, retries); break; case -EBUSY: /* set up timer, try later */ PRINT_WARN ("cqr %p: 0x%04x busy, %d retries left\n", cqr, dasd_info[di]->info.devno, retries); break; default: PRINT_WARN ("cqr %p: 0x%04x %d, %d retries left\n", cqr, rc, dasd_info[di]->info.devno, retries); break; } } while (rc && --retries); if (rc) { if (atomic_compare_and_swap (CQR_STATUS_IN_IO, CQR_STATUS_ERROR, &cqr->status)) { PRINT_WARN ("start_IO:(done) status changed %d\n", atomic_read (&cqr->status)); atomic_set (&cqr->status, CQR_STATUS_ERROR); } } return rc;}static inlinevoiddasd_end_cqr (cqr_t * cqr, int uptodate){ struct request *req = cqr->req; asm volatile ("STCK %0":"=m" (cqr->endclk));#ifdef DASD_PROFILE dasd_profile_add (cqr);#endif /* DASD_PROFILE */ dasd_chanq_deq (&dasd_info[cqr->devindex]->queue, cqr); if (req) { dasd_end_request (req, uptodate); }}voiddasd_dump_sense (devstat_t * stat){ int sl, sct; if ( ! stat->flag | DEVSTAT_FLAG_SENSE_AVAIL) { PRINT_INFO("I/O status w/o sense data"); } else { printk (KERN_INFO PRINTK_HEADER "-------------------I/O result:-----------\n"); for (sl = 0; sl < 4; sl++) { printk (KERN_INFO PRINTK_HEADER "Sense:"); for (sct = 0; sct < 8; sct++) { printk (" %2d:0x%02X", 8 * sl + sct, stat->ii.sense.data[8 * sl + sct]); } printk ("\n"); } }}static int register_dasd_last (int di){ int rc = 0; int minor; struct buffer_head *bh; rc = dasd_disciplines[dasd_info[di]->type]->fill_sizes_last (di); switch (rc) { case -EMEDIUMTYPE: dasd_info[di]->flags |= DASD_INFO_FLAGS_NOT_FORMATTED; break; } PRINT_INFO ("%ld kB <- 'soft'-block: %d, hardsect %d Bytes\n", dasd_info[di]->sizes.kbytes, dasd_info[di]->sizes.bp_block, dasd_info[di]->sizes.bp_sector); switch (dasd_info[di]->type) {#ifdef CONFIG_DASD_ECKD case dasd_eckd: dasd_info[di]->sizes.label_block = 2; break;#endif /* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSK case dasd_mdsk: dasd_info[di]->sizes.label_block = -1; break;#endif /* CONFIG_DASD_ECKD */ default: INTERNAL_CHECK ("Unknown dasd type %d\n", dasd_info[di]->type); } minor = di << PARTN_BITS; dasd_blks[minor] = dasd_info[di]->sizes.kbytes; dasd_secsize[minor] = dasd_info[di]->sizes.bp_sector; dasd_blksize[minor] = dasd_info[di]->sizes.bp_block; dasd_maxsecs[minor] = 252<<dasd_info[di]->sizes.s2b_shift; dasd_secsize[minor+1] = dasd_info[di]->sizes.bp_sector; dasd_blksize[minor+1] = dasd_info[di]->sizes.bp_block; dasd_maxsecs[minor+1] = 252<<dasd_info[di]->sizes.s2b_shift; {#define DASD_NAME_PREFIX "dasd_" char * name = (char *) kmalloc ( 1+strlen (DASD_NAME_PREFIX) + 2 /* 0x */ + 4 /* devno */, GFP_KERNEL); sprintf ( name , DASD_NAME_PREFIX "%04x%c", dasd_info[di]->info.devno,'\0' ); dasd_info[di] -> devfs_entry = devfs_register ( NULL /* dir */, name, DEVFS_FL_DEFAULT /* flags */, DASD_MAJOR, minor, 0755 /* mode */, &dasd_device_operations, (void *)dasd_info[di]); } /* end of that stuff */ return rc;}void dasd_partn_detect ( int di ) { int minor = di << PARTN_BITS; LOOP_CONTROL ("Setting partitions of DASD %d\n", di); register_disk (&dd_gendisk, MKDEV(DASD_MAJOR,minor), 1 << PARTN_BITS, &dasd_device_operations, dasd_info[di]->sizes.kbytes << 1);}voiddasd_do_chanq (void){ dasd_chanq_t *qp = NULL; cqr_t *cqr; long flags; int irq; int tasks; atomic_set (&bh_scheduled, 0); dasd_debug (0xc4c40000); /* DD */ while ((tasks = atomic_read(&chanq_tasks)) != 0) {/* initialization and wraparound */ if (qp == NULL) { dasd_debug (0xc4c46df0); /* DD_0 */ qp = cq_head; if (!qp) { dasd_debug (0xc4c46ff1); /* DD?1 */ dasd_debug (tasks); PRINT_ERR("Mismatch of NULL queue pointer and " "still %d chanq_tasks to do!!\n" "Please send output of /proc/dasd/debug " "to Linux390@de.ibm.com\n", tasks); atomic_set(&chanq_tasks,0); break; } }/* Get first request */ dasd_debug ((unsigned long) qp); cqr = (cqr_t *) (qp->head);/* empty queue -> dequeue and proceed */ if (!cqr) { dasd_chanq_t *nqp = qp->next_q; cql_deq (qp); qp = nqp; continue; }/* process all requests on that queue */ do { cqr_t *next; dasd_debug ((unsigned long) cqr); /* cqr */ if (cqr->magic != DASD_MAGIC) { dasd_debug (0xc4c46ff2); /* DD?2 */ panic ( PRINTK_HEADER "do_cq:" "magic mismatch %p -> %x\n", cqr, cqr -> magic); break; } irq = dasd_info[cqr->devindex]->info.irq; s390irq_spin_lock_irqsave (irq, flags); switch (atomic_read (&cqr->status)) { case CQR_STATUS_IN_IO: dasd_debug (0xc4c4c9d6); /* DDIO */ cqr = NULL; break; case CQR_STATUS_QUEUED: dasd_debug (0xc4c4e2e3); /* DDST */ if (dasd_start_IO (cqr) == 0) { atomic_dec (&chanq_tasks); cqr = NULL; } break; case CQR_STATUS_ERROR: dasd_debug (0xc4c4c5d9); /* DDER */ dasd_dump_sense (cqr->dstat); if ( ++ cqr->retries < 2 ) { atomic_set (&cqr->status, CQR_STATUS_QUEUED); dasd_debug (0xc4c4e2e3); /* DDST */ if (dasd_start_IO (cqr) == 0) { atomic_dec ( &qp -> dirty_requests); atomic_dec (&chanq_tasks); cqr = NULL; } } else { atomic_set (&cqr->status, CQR_STATUS_FAILED); } break; case CQR_STATUS_DONE: next = cqr->next; dasd_debug (0xc4c49692); /* DDok */ dasd_end_cqr (cqr, 1); atomic_dec (&chanq_tasks); cqr = next; break; case CQR_STATUS_FAILED: next = cqr->next; dasd_debug (0xc4c47a7a); /* DD:: */ if ( ! ( dasd_info[cqr->devindex]-> flags & DASD_INFO_FLAGS_INITIALIZED ) ) { dasd_info[cqr->devindex]-> flags |= DASD_INFO_FLAGS_INITIALIZED | DASD_INFO_FLAGS_NOT_FORMATTED; } dasd_end_cqr (cqr, 0); atomic_dec ( &qp -> dirty_requests ); atomic_dec (&chanq_tasks); cqr = next; break; default: PRINT_WARN ("unknown cqrstatus\n"); cqr = NULL; } s390irq_spin_unlock_irqrestore (irq, flags); } while (cqr); qp = qp->next_q; } spin_lock (&io_request_lock); do_dasd_request (&blk_dev[DASD_MAJOR].request_queue); spin_unlock (&io_request_lock); dasd_debug (0xc4c46d6d); /* DD__ */}/* The request_fn is called from ll_rw_blk for any new request. We use it to feed the chanqs. This implementation assumes we are serialized by the io_request_lock. */#define QUEUE_THRESHOLD 5voiddo_dasd_request (request_queue_t *queue){ struct request *req; cqr_t *cqr; dasd_chanq_t *q; long flags; int di, irq, go; int broken, busy; dasd_debug (0xc4d90000); /* DR */ dasd_debug ((unsigned long) __builtin_return_address(0)); go = 1; while (go && !list_empty(&queue->queue_head)) { req = blkdev_entry_next_request(&queue->queue_head); req = blkdev_entry_next_request(&queue->queue_head); di = DEVICE_NR (req->rq_dev); dasd_debug ((unsigned long) req); /* req */ dasd_debug (0xc4d90000 + /* DR## */ ((((di/16)<9?(di/16)+0xf0:(di/16)+0xc1))<<8) + (((di%16)<9?(di%16)+0xf0:(di%16)+0xc1))); irq = dasd_info[di]->info.irq; s390irq_spin_lock_irqsave (irq, flags); q = &dasd_info[di]->queue; busy = atomic_read(&q->flags) & DASD_CHANQ_BUSY; broken = atomic_read(&q->flags)&DASD_REQUEST_Q_BROKEN; if ( ! busy || ( ! broken && (req->nr_sectors >= QUEUE_SECTORS))) { blkdev_dequeue_request(req); /* printk ( KERN_INFO "0x%04x %c %d %d\n", req->rq_dev,req->cmd ?'w':'r', req->sector,req->nr_sectors); */ cqr = dasd_cqr_from_req (req); if (!cqr) { dasd_debug (0xc4d96ff1); /* DR?1 */ dasd_end_request (req, 0); goto cont; } dasd_debug ((unsigned long) cqr); /* cqr */ dasd_chanq_enq (q, cqr); if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) { cql_enq_head (q); } if ( ! busy ) { atomic_clear_mask (DASD_REQUEST_Q_BROKEN, &q->flags ); if (atomic_read( &q->dirty_requests) == 0 ) { if ( dasd_start_IO (cqr) == 0 ) { } else { atomic_inc (&chanq_tasks); schedule_bh (dasd_do_chanq); } } } } else { dasd_debug (0xc4d9c2d9); /* DRBR */ atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags ); go = 0; } cont: s390irq_spin_unlock_irqrestore (irq, flags); } dasd_debug (0xc4d96d6d); /* DR__ */}voiddasd_handler (int irq, void *ds, struct pt_regs *regs){ devstat_t *stat = (devstat_t *) ds; int ip; cqr_t *cqr; int done_fast_io = 0; dasd_debug (0xc4c80000); /* DH */ if (!stat) PRINT_ERR ("handler called without devstat"); ip = stat->intparm; dasd_debug (ip); /* intparm */ switch (ip) { /* filter special intparms... */ case 0x00000000: /* no intparm: unsolicited interrupt */ dasd_debug (0xc4c8a489); /* DHui */ PRINT_INFO ("Unsolicited interrupt on device %04X\n", stat->devno); dasd_dump_sense (stat); return; default: if (ip & 0x80000001) { dasd_debug (0xc4c8a489); /* DHui */ PRINT_INFO ("Spurious interrupt %08x on device %04X\n", ip, stat->devno); return; } cqr = (cqr_t *) ip; if (cqr->magic != DASD_MAGIC) { dasd_debug (0xc4c86ff1); /* DH?1 */ PRINT_ERR ("handler:magic mismatch on %p %08x\n", cqr, cqr->magic);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -