/* * Allocate memory for a new zvol_state_t and setup the required * request queue and generic disk structures for the block device. */ static zvol_state_t * zvol_alloc(dev_t dev, const char *name) { zvol_state_t *zv; zv = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP); if (zv == NULL) goto out; zv->zv_queue = blk_init_queue(zvol_request, &zv->zv_lock); if (zv->zv_queue == NULL) goto out_kmem; #ifdef HAVE_BLK_QUEUE_FLUSH blk_queue_flush(zv->zv_queue, VDEV_REQ_FLUSH | VDEV_REQ_FUA); #else blk_queue_ordered(zv->zv_queue, QUEUE_ORDERED_DRAIN, NULL); #endif /* HAVE_BLK_QUEUE_FLUSH */ zv->zv_disk = alloc_disk(ZVOL_MINORS); if (zv->zv_disk == NULL) goto out_queue; zv->zv_queue->queuedata = zv; zv->zv_dev = dev; zv->zv_open_count = 0; strlcpy(zv->zv_name, name, MAXNAMELEN); mutex_init(&zv->zv_znode.z_range_lock, NULL, MUTEX_DEFAULT, NULL); avl_create(&zv->zv_znode.z_range_avl, zfs_range_compare, sizeof (rl_t), offsetof(rl_t, r_node)); zv->zv_znode.z_is_zvol = TRUE; spin_lock_init(&zv->zv_lock); list_link_init(&zv->zv_next); zv->zv_disk->major = zvol_major; zv->zv_disk->first_minor = (dev & MINORMASK); zv->zv_disk->fops = &zvol_ops; zv->zv_disk->private_data = zv; zv->zv_disk->queue = zv->zv_queue; snprintf(zv->zv_disk->disk_name, DISK_NAME_LEN, "%s%d", ZVOL_DEV_NAME, (dev & MINORMASK)); return zv; out_queue: blk_cleanup_queue(zv->zv_queue); out_kmem: kmem_free(zv, sizeof (zvol_state_t)); out: return NULL; }
/** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; mq->queue->queuedata = mq; mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_hw_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; if (bouncesz > 512) { mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mq->bounce_buf) { printk(KERN_WARNING "%s: unable to " "allocate bounce buffer\n", mmc_card_name(card)); } } if (mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_sectors(mq->queue, bouncesz / 512); blk_queue_max_phys_segments(mq->queue, bouncesz / 512); blk_queue_max_hw_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mq->sg = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, 1); mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->bounce_sg, bouncesz / 512); } } #endif if (!mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, host->max_phys_segs); } init_MUTEX(&mq->thread_sem); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; cleanup_queue: if (mq->sg) kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
/* * Allocate memory for a new zvol_state_t and setup the required * request queue and generic disk structures for the block device. */ static zvol_state_t * zvol_alloc(dev_t dev, const char *name) { zvol_state_t *zv; int error = 0; zv = kmem_zalloc(sizeof (zvol_state_t), KM_PUSHPAGE); spin_lock_init(&zv->zv_lock); list_link_init(&zv->zv_next); zv->zv_queue = blk_init_queue(zvol_request, &zv->zv_lock); if (zv->zv_queue == NULL) goto out_kmem; #ifdef HAVE_ELEVATOR_CHANGE error = elevator_change(zv->zv_queue, "noop"); #endif /* HAVE_ELEVATOR_CHANGE */ if (error) { printk("ZFS: Unable to set \"%s\" scheduler for zvol %s: %d\n", "noop", name, error); goto out_queue; } #ifdef HAVE_BLK_QUEUE_FLUSH blk_queue_flush(zv->zv_queue, VDEV_REQ_FLUSH | VDEV_REQ_FUA); #else blk_queue_ordered(zv->zv_queue, QUEUE_ORDERED_DRAIN, NULL); #endif /* HAVE_BLK_QUEUE_FLUSH */ zv->zv_disk = alloc_disk(ZVOL_MINORS); if (zv->zv_disk == NULL) goto out_queue; zv->zv_queue->queuedata = zv; zv->zv_dev = dev; zv->zv_open_count = 0; strlcpy(zv->zv_name, name, MAXNAMELEN); mutex_init(&zv->zv_znode.z_range_lock, NULL, MUTEX_DEFAULT, NULL); avl_create(&zv->zv_znode.z_range_avl, zfs_range_compare, sizeof (rl_t), offsetof(rl_t, r_node)); zv->zv_znode.z_is_zvol = TRUE; zv->zv_disk->major = zvol_major; zv->zv_disk->first_minor = (dev & MINORMASK); zv->zv_disk->fops = &zvol_ops; zv->zv_disk->private_data = zv; zv->zv_disk->queue = zv->zv_queue; snprintf(zv->zv_disk->disk_name, DISK_NAME_LEN, "%s%d", ZVOL_DEV_NAME, (dev & MINORMASK)); return (zv); out_queue: blk_cleanup_queue(zv->zv_queue); out_kmem: kmem_free(zv, sizeof (zvol_state_t)); return (NULL); }
/* Create system device file for the enabled slot. */ ndas_error_t slot_enable(int s) { ndas_error_t ret = NDAS_ERROR_INTERNAL; int got; struct ndas_slot* slot = NDAS_GET_SLOT_DEV(s); dbgl_blk(3, "ing s#=%d slot=%p",s, slot); got = try_module_get(THIS_MODULE); MOD_INC_USE_COUNT; if ( slot == NULL) goto out1; if ( slot->enabled ) { dbgl_blk(1, "already enabled"); ret = NDAS_OK; goto out2; } ret = ndas_query_slot(s, &slot->info); if ( !NDAS_SUCCESS(ret) ) { dbgl_blk(1, "fail ndas_query_slot"); goto out2; } dbgl_blk(1, "mode=%d", slot->info.mode); slot->enabled = 1; #if LINUX_VERSION_25_ABOVE slot->disk = NULL; spin_lock_init(&slot->lock); slot->queue = blk_init_queue( nblk_request_proc, &slot->lock ); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,33)) blk_queue_max_phys_segments(slot->queue, ND_BLK_MAX_REQ_SEGMENT); blk_queue_max_hw_segments(slot->queue, ND_BLK_MAX_REQ_SEGMENT); #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33)) blk_queue_max_segments(slot->queue, ND_BLK_MAX_REQ_SEGMENT); //renamed in 2.6.34 //blk_queue_max_hw_segments(slot->queue, ND_BLK_MAX_REQ_SEGMENT); //removed in 2.6.34 #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) blk_queue_logical_block_size(slot->queue, slot->info.sector_size); #else blk_queue_hardsect_size(slot->queue, slot->info.sector_size); #endif #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,33)) blk_queue_max_sectors(slot->queue, DEFAULT_ND_MAX_SECTORS); #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33)) blk_queue_max_hw_sectors(slot->queue, DEFAULT_ND_MAX_SECTORS); //renamed in 2.6.34 #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)) // Set ordered queue property. #if 0 blk_queue_ordered(slot->queue, QUEUE_ORDERED_TAG_FLUSH, nblk_prepare_flush); #endif #endif slot->disk = alloc_disk(NR_PARTITION); if ( slot->disk == NULL ) { slot->enabled = 0; dbgl_blk(1, "fail alloc disk"); goto out2; } slot->disk->major = NDAS_BLK_MAJOR; slot->disk->first_minor = (s - NDAS_FIRST_SLOT_NR) << PARTN_BITS; slot->disk->fops = &ndas_fops; slot->disk->queue = slot->queue; slot->disk->private_data = (void*) (long)s; slot->queue_flags = 0; dbgl_blk(1, "mode=%d", slot->info.mode); if ( slot->info.mode == NDAS_DISK_MODE_SINGLE || slot->info.mode == NDAS_DISK_MODE_ATAPI || slot->info.mode == NDAS_DISK_MODE_MEDIAJUKE) { char short_serial[NDAS_SERIAL_SHORT_LENGTH + 1]; if (strlen(slot->info.ndas_serial) > 8) { /* Extended serial number is too long as sysfs object name. Use last 8 digit only */ strncpy( short_serial, slot->info.ndas_serial + ( NDAS_SERIAL_EXTEND_LENGTH - NDAS_SERIAL_SHORT_LENGTH), 8); } else { strncpy(short_serial, slot->info.ndas_serial, 8); } short_serial[8] =0; snprintf(slot->devname, sizeof(slot->devname)-1, "ndas-%s-%d", short_serial, slot->info.unit ); strcpy(slot->disk->disk_name, slot->devname); dbgl_blk(1, "just set slot->disk->%s, slot->%s", slot->disk->disk_name, slot->devname ); #if !LINUX_VERSION_DEVFS_REMOVED_COMPLETELY strcpy(slot->disk->devfs_name, slot->devname); #endif set_capacity(slot->disk, slot->info.sectors); dbgl_blk(1, "just set capacity slot->disk, slot->info.sectors:%llu", slot->info.sectors); } else { /* Other mode is not implemented */ } if (slot->info.mode == NDAS_DISK_MODE_ATAPI) { slot->disk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE; dbgl_blk(1, "just set slot->disk->flags"); #if 0 kref_init(&slot->ndascd.kref); #endif } dbgl_blk(4, "adding disk: slot=%d, first_minor=%d, capacity=%llu", s, slot->disk->first_minor, slot->info.sectors); add_disk(slot->disk); dbgl_blk(1, "added disk: slot=%d", s); #ifndef NDAS_DONT_CARE_SCHEDULER #if LINUX_VERSION_AVOID_CFQ_SCHEDULER #if CONFIG_SYSFS sal_assert(slot->queue->kobj.ktype); sal_assert(slot->queue->kobj.ktype->default_attrs); { struct queue_sysfs_entry { struct attribute attr; ssize_t (*show)(struct request_queue *, char *); ssize_t (*store)(struct request_queue *, const char *, size_t); }; struct attribute *attr = slot->queue->kobj.ktype->default_attrs[4]; struct queue_sysfs_entry *entry = container_of(attr , struct queue_sysfs_entry, attr); //dbgl_blk(1, "now to set the scheduler: slot-queue=%d, scheduler==%s, scheduler_len=%d", slot->queue, NDAS_QUEUE_SCHEDULER, strlen(NDAS_QUEUE_SCHEDULER)); entry->store(slot->queue,NDAS_QUEUE_SCHEDULER,strlen(NDAS_QUEUE_SCHEDULER)); } #else #error "NDAS driver doesn't work well with CFQ scheduler of 2.6.13 or above kernel." \ "if you forcely want to use it, please specify compiler flags by " \ "export NDAS_EXTRA_CFLAGS=\"-DNDAS_DONT_CARE_SCHEDULER\" "\ "then compile the source again." #endif #endif #endif printk("ndas: /dev/%s enabled\n" , slot->devname); #else /* < LINUX_VERSION_25_ABOVE */ dbgl_blk(4, "blksize=%d", DEFAULT_ND_BLKSIZE); dbgl_blk(4, "size=%lld", slot->info.sectors); dbgl_blk(1, "hardsectsize=%d", slot->info.sector_size); ndas_ops_set_blk_size( s, DEFAULT_ND_BLKSIZE, slot->info.sectors, slot->info.sector_size, DEFAULT_ND_MAX_SECTORS ); #ifdef NDAS_DEVFS printk("ndas: /dev/nd/disc%d enabled\n" , s - NDAS_FIRST_SLOT_NR); #else printk("ndas: /dev/nd%c enabled\n" , s + 'a' - NDAS_FIRST_SLOT_NR); #endif #endif //up(&slot->mutex); #ifdef NDAS_MSHARE if(NDAS_GET_SLOT_DEV(s)->info.mode == NDAS_DISK_MODE_MEDIAJUKE) { ndas_CheckFormat(s); } #endif #if !LINUX_VERSION_25_ABOVE ndas_ops_read_partition(s); #endif dbgl_blk(3, "ed"); return NDAS_OK; out2: //up(&slot->mutex); out1: if ( got ) module_put(THIS_MODULE); MOD_DEC_USE_COUNT; return ret; }
/** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; mq->queue->queuedata = mq; mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); /* Set max discard size, << 11 converts to megabytes in sectors */ blk_queue_max_discard_sectors(mq->queue, 16 << 11); if (card->csd.cmdclass & CCC_ERASE) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue); /* * Calculating a correct span is way to messy if this * assumption is broken, so remove the erase support */ if (unlikely(mmc_card_blockaddr(card) && (card->csd.erase_size % 512))) queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mq->queue); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_hw_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; if (bouncesz > 512) { mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mq->bounce_buf) { printk(KERN_WARNING "%s: unable to " "allocate bounce buffer\n", mmc_card_name(card)); } } if (mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); blk_queue_max_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mq->sg = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, 1); mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->bounce_sg, bouncesz / 512); } } #endif if (!mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, host->max_phys_segs); } init_MUTEX(&mq->thread_sem); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; cleanup_queue: if (mq->sg) kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
/** * @brief Card initial function. * @param work[in]: Work structure. * @return None. */ static void gp_sdcard_work_init(struct work_struct *work) { gpSDInfo_t* sd = container_of(work, gpSDInfo_t,init); int pin_handle; pin_handle = gp_board_pin_func_request((sd->device_id==0)?GP_PIN_SD0:GP_PIN_SD1, GP_BOARD_WAIT_FOREVER); if(pin_handle<0) { DERROR("SD%d: can't get pin handle\n", sd->device_id); goto init_work_end; } /* ----- Initial SD module (controller) ----- */ gpHalSDInit(sd->device_id); /* ----- Initial SD card ----- */ gp_sdcard_cardinit(sd); gp_board_pin_func_release(pin_handle); if(sd->present==1) { if(sd->card_type == SDIO) { sd->pin_handle = gp_board_pin_func_request((sd->device_id==0)?GP_PIN_SD0:GP_PIN_SD1, GP_BOARD_WAIT_FOREVER); if(sd->pin_handle<0) { DERROR("SD%d: can't get pin handle\n", sd->device_id); goto init_work_end; } DEBUG("SDIO card detected\n"); gp_sdio_insert_device(sd->device_id, sd->RCA); } else { sd->queue = blk_init_queue(gp_sdcard_request, &sd->lock); if(sd->queue==NULL) { DERROR("NO MEMORY: queue\n"); goto init_work_end; } blk_queue_ordered(sd->queue, QUEUE_ORDERED_DRAIN, NULL); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sd->queue); blk_queue_logical_block_size(sd->queue, 512); blk_queue_max_sectors(sd->queue, SD_MAX_SECTORS ); blk_queue_max_phys_segments(sd->queue, SD_MAX_PHY_SEGMENTS); blk_queue_max_hw_segments(sd->queue, SD_MAX_HW_SEGMENTS); blk_queue_max_segment_size(sd->queue, SD_MAX_PHY_SEGMENTS_SIZE); /* ----- Initial scatter list ----- */ sd->sg = kmalloc(sizeof(struct scatterlist) *SD_MAX_PHY_SEGMENTS, GFP_KERNEL); if (!sd->sg) { DERROR("NO MEMORY: queue\n"); goto fail_thread; } sg_init_table(sd->sg, SD_MAX_PHY_SEGMENTS); init_MUTEX(&sd->thread_sem); /* ----- Enable thread ----- */ sd->thread = kthread_run(gp_sdcard_queue_thread, sd, "sd-qd"); if (IS_ERR(sd->thread)) { goto fail_thread; } sd->queue->queuedata = sd; /* ----- Setup gendisk structure ----- */ sd->gd = alloc_disk(SD_MINORS); if (sd->gd==NULL) { DERROR("NO MEMORY: gendisk\n"); blk_cleanup_queue(sd->queue); goto fail_gd; } /* ----- Set gendisk structure ----- */ sd->gd->major = sd_major; sd->gd->first_minor = sd->device_id*SD_MINORS; sd->gd->fops = &gp_sdcard_ops; sd->gd->queue = sd->queue; sd->gd->private_data = sd; snprintf (sd->gd->disk_name, 32, "sdcard%c", sd->device_id + 'a'); set_capacity(sd->gd,sd->capacity); add_disk(sd->gd); } goto init_work_end; } else { DERROR("Initial fail\n"); goto init_work_end; } fail_gd: /* ----- Then terminate our worker thread ----- */ kthread_stop(sd->thread); fail_thread: if (sd->sg) kfree(sd->sg); sd->sg = NULL; blk_cleanup_queue (sd->queue); init_work_end: sd->timer.expires = jiffies + SD_CD_POLL; add_timer(&sd->timer); }
/** * @brief Card initial function. * @param work[in]: Work structure. * @return None. */ static void gp_sdcard_work_init(struct work_struct *work) { gpSDInfo_t* sd = container_of(work, gpSDInfo_t,init); int pin_handle; int ret = 0,i=0; int pin_id; if(sd->device_id == 0) pin_id = GP_PIN_SD0; else if(sd->device_id == 1) pin_id = GP_PIN_SD1; else pin_id = GP_PIN_SD2; pin_handle = gp_board_pin_func_request( pin_id, GP_BOARD_WAIT_FOREVER); if(pin_handle<0) { DERROR("[%d]: can't get pin handle\n", sd->device_id); goto init_work_end; } /* ----- chris: Set Pin state for SD before power on ----- */ sd->sd_func->set_power(1); /* ----- chris: delay 250ms after card power on ----- */ msleep(250); /* ----- Initial SD card ----- */ ret = gp_sdcard_cardinit(sd); if (ret != 0) { DERROR("[%d]: initial fail\n",sd->device_id); gp_board_pin_func_release(pin_handle); goto init_work_end; } gp_board_pin_func_release(pin_handle); if(sd->present==1) { if(sd->card_type == SDIO) { sd->pin_handle = gp_board_pin_func_request(pin_id, GP_BOARD_WAIT_FOREVER); if(sd->pin_handle<0) { DERROR("[%d]: can't get pin handle\n", sd->device_id); goto init_work_end; } DEBUG("SDIO card detected\n"); gp_sdio_insert_device(sd->device_id, sd->RCA); } else { unsigned int cnt =0; /* ----- Wait 30 second for all process close handle ----- */ while((sd->users)&&cnt<120) { msleep(250); cnt++; } if(sd->users) { DERROR("Some handle do not free\n"); } if(sd->status) { gp_sdcard_blk_put(sd); sd->status = 0; } sd->handle_dma = gp_apbdma0_request(1000); if(sd->handle_dma==0) goto init_work_end; sd->queue = blk_init_queue(gp_sdcard_request, &sd->lock); if(sd->queue==NULL) { DERROR("NO MEMORY: queue\n"); goto fail_queue; } blk_queue_ordered(sd->queue, QUEUE_ORDERED_DRAIN, NULL); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sd->queue); blk_queue_logical_block_size(sd->queue, 512); blk_queue_max_sectors(sd->queue, SD_MAX_SECTORS ); blk_queue_max_phys_segments(sd->queue, SD_MAX_PHY_SEGMENTS); blk_queue_max_hw_segments(sd->queue, SD_MAX_HW_SEGMENTS); blk_queue_max_segment_size(sd->queue, SD_MAX_PHY_SEGMENTS_SIZE); /* ----- Initial scatter list ----- */ sd->sg = kmalloc(sizeof(struct scatterlist) *SD_MAX_PHY_SEGMENTS, GFP_KERNEL); if (!sd->sg) { DERROR("NO MEMORY: queue\n"); goto fail_thread; } sg_init_table(sd->sg, SD_MAX_PHY_SEGMENTS); init_MUTEX(&sd->thread_sem); /* ----- Enable thread ----- */ sd->thread = kthread_run(gp_sdcard_queue_thread, sd, "sd-qd"); if (IS_ERR(sd->thread)) { goto fail_thread; } sd->queue->queuedata = sd; /* ----- Check SD card for GP special header ----- */ if(gp_sdcard_parse_header(sd)<0) { goto fail_gd; } /* ----- Setup gendisk structure ----- */ sd->gd = alloc_disk(SD_MINORS); if (sd->gd==NULL) { DERROR("NO MEMORY: gendisk\n"); blk_cleanup_queue(sd->queue); goto fail_gd; } /* ----- Set gendisk structure ----- */ sd->gd->major = sd_major; sd->gd->first_minor = sd->device_id*SD_MINORS; sd->gd->fops = &gp_sdcard_ops; sd->gd->queue = sd->queue; sd->gd->private_data = sd; snprintf (sd->gd->disk_name, 32, "sdcard%c", sd->device_id + 'a'); /* ----- Set GP partition ----- */ if(sd->partition.activity) { set_capacity(sd->gd,0); add_disk(sd->gd); for(i=0;i<MAX_SD_PART;i++) { if(sd->partition.capacity[i]==0) continue; gp_add_partition(sd->gd,i+1,sd->partition.offset[i],sd->partition.capacity[i],ADDPART_FLAG_WHOLEDISK); } } /* ----- Normal Setting ----- */ else { set_capacity(sd->gd,sd->capacity); add_disk(sd->gd); } } //DEBUG("Initial success\n"); goto init_work_end; } else { DERROR("Initial fail\n"); goto init_work_end; } fail_gd: /* ----- Then terminate our worker thread ----- */ kthread_stop(sd->thread); sd->thread = NULL; fail_thread: if (sd->sg) kfree(sd->sg); sd->sg = NULL; blk_cleanup_queue (sd->queue); sd->queue = NULL; fail_queue: if(sd->handle_dma) gp_apbdma0_release(sd->handle_dma); sd->handle_dma = 0; /* ----- For re-initialize ----- */ sd->present = 0; init_work_end: sd->timer.expires = jiffies + SD_CD_POLL; add_timer(&sd->timer); }
int td_linux_block_create(struct td_osdev *dev) { int rc; struct request_queue *queue; unsigned bio_sector_size = dev->block_params.bio_sector_size; unsigned hw_sector_size = dev->block_params.hw_sector_size; /* very simple sector size support */ if (!bio_sector_size || bio_sector_size & 511 || bio_sector_size > 4096) { td_os_err(dev, "bio sector size of %u is not supported\n", bio_sector_size); return -EINVAL; } /* MetaData is reported here */ if (hw_sector_size == 520) hw_sector_size = 512; if (!hw_sector_size || hw_sector_size & 511 || hw_sector_size > 4096) { td_os_err(dev, "hw sector size of %u is not supported\n", hw_sector_size); return -EINVAL; } td_os_notice(dev, " - Set capacity to %llu (%u bytes/sector)\n", dev->block_params.capacity, dev->block_params.hw_sector_size); /* create a new bio queue */ queue = blk_alloc_queue(GFP_KERNEL); if (!queue) { td_os_err(dev, "Error allocating disk queue.\n"); rc = -ENOMEM; goto error_alloc_queue; } #ifdef QUEUE_FLAG_NONROT queue_flag_set_unlocked(QUEUE_FLAG_NONROT, queue); #endif switch (dev->type) { case TD_OSDEV_DEVICE: blk_queue_make_request(queue, td_device_make_request); dev->_bio_error = td_device_bio_error; break; case TD_OSDEV_RAID: blk_queue_make_request(queue, td_raid_make_request); dev->_bio_error = td_raid_bio_error; break; default: td_os_err(dev, "Unkonwn OS Type, cannot register block request handler\n"); goto error_config_queue; } queue->queuedata = dev; #if defined QUEUE_FLAG_PLUGGED queue->unplug_fn = td_device_queue_unplug; #endif /* configure queue ordering */ /* in QUEUE_ORDERED_DRAIN we will get BARRIERS after the queue has * been drained. */ #if defined KABI__blk_queue_ordered #if KABI__blk_queue_ordered == 2 blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN); #elif KABI__blk_queue_ordered == 3 blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN, NULL); #else #error unhandled value of KABI__blk_queue_ordered #endif #elif defined KABI__blk_queue_flush /* * blk_queue_ordered was replaced with blk_queue_flush * The default implementation is QUEUE_ORDERED_DRAIN */ blk_queue_flush(queue, 0); #else #error undefined KABI__blk_queue_flush or KABI__blk_queue_ordered #endif /* max out the throttling */ #ifdef KABI__blk_queue_max_hw_sectors blk_queue_max_hw_sectors(queue, dev->block_params.bio_max_bytes/512); #elif defined KABI__blk_queue_max_sectors blk_queue_max_sectors(queue, dev->block_params.bio_max_bytes/512); #else td_os_err(dev, "No kernel API for maximum sectors\n"); #endif #if defined KABI__blk_queue_max_segments blk_queue_max_segments(queue, BLK_MAX_SEGMENTS); #elif defined KABI__blk_queue_max_phys_segments blk_queue_max_phys_segments(queue, MAX_SEGMENT_SIZE); blk_queue_max_hw_segments(queue, MAX_SEGMENT_SIZE); #else td_os_err(dev, "No kernel API for maximum segments\n"); #endif blk_queue_max_segment_size(queue, dev->block_params.bio_max_bytes); blk_queue_bounce_limit(queue, BLK_BOUNCE_ANY); /* setup paged based access */ td_os_info(dev, "Set queue physical block size to %u\n", hw_sector_size); #ifdef KABI__blk_queue_physical_block_size blk_queue_physical_block_size(queue, hw_sector_size); #elif defined KABI__blk_queue_hardsect_size blk_queue_hardsect_size(queue, hw_sector_size); #else td_os_err(dev, "No kernel API for physical sector size\n"); #endif #ifdef KABI__blk_queue_logical_block_size td_os_info(dev, "Set queue logical block size to %u\n", bio_sector_size); blk_queue_logical_block_size(queue, bio_sector_size); #else td_os_err(dev, "No kernel API for logical block size\n"); #endif #ifdef KABI__blk_queue_io_min td_os_info(dev, "Set queue io_min to %u\n", bio_sector_size); blk_queue_io_min(queue, bio_sector_size); #else td_os_err(dev, "No kernel API for minimum IO size\n"); #endif #ifdef KABI__blk_queue_io_opt td_os_info(dev, "Set queue io_opt to %u\n", dev->block_params.bio_max_bytes); blk_queue_io_opt(queue, dev->block_params.bio_max_bytes); #else td_os_err(dev, "No kernel API for optimal IO size\n"); #endif #if 0 if (dev->block_params.discard) { int did_something = 0; #if defined KABI__blk_queue_discard_granularity queue->limits.discard_granularity = bio_sector_size; did_something++; #endif #ifdef KABI__blk_queue_max_discard_sectors /* 0xFFFF (max sector size of chunk on trim) * 64 * # SSD */ blk_queue_max_discard_sectors(queue, TD_MAX_DISCARD_LBA_COUNT * 2); did_something++; #endif #ifdef KABI__blk_queue_discard_zeroes_data queue->limits.discard_zeroes_data = 1; did_something++; #endif #ifdef KABI__queue_flag_set_unlocked queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, queue); did_something++; #endif /* Maybe some day.. But not today. queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, queue); */ if (did_something) td_os_info(dev, "Enabling discard support\n"); else td_os_notice(dev, "No kernel API for discard support\n"); } else { td_os_info(dev, "No DISCARD support enabled\n"); } #else /* bug 7444 */ if (dev->block_params.discard) td_os_info(dev, "Device supports DISCARD but is currently being forced disabled\n"); #endif /* assign */ dev->queue = queue; return 0; error_config_queue: blk_cleanup_queue(dev->queue); dev->queue = NULL; error_alloc_queue: return rc; }