Re: [PATCH v2 3/3] cxlflash: Virtual LUN support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07/16/2015 06:26 PM, Matthew R. Ochs wrote:
> +
> +/**
> + * ba_clone() - frees a block from the block allocator
> + * @ba_lun:	Block allocator from which to allocate a block.
> + * @to_free:	Block to free.
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +static int ba_clone(struct ba_lun *ba_lun, u64 to_clone)
> +{
> +	struct ba_lun_info *lun_info =
> +	    (struct ba_lun_info *)ba_lun->ba_lun_handle;
> +
> +	if (validate_alloc(lun_info, to_clone)) {
> +		pr_err("%s: AUN %llX is not allocated on lun_id %llX\n",
> +		       __func__, to_clone, ba_lun->lun_id);

Suggest using dev_err here instead to scope the error to the adapter.

> +		return -1;

Might be nice to return a better error to the user in both of the error cases
in this code.

> +	}
> +
> +	pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n",
> +		 __func__, to_clone, ba_lun->lun_id);
> +
> +	if (lun_info->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) {
> +		pr_err("%s: AUN %llX on lun_id %llX hit max clones already\n",
> +		       __func__, to_clone, ba_lun->lun_id);
> +		return -1;
> +	}
> +
> +	lun_info->aun_clone_map[to_clone]++;
> +
> +	return 0;
> +}
> +


> +
> +/**
> + * init_ba() - initializes and allocates a block allocator
> + * @lun_info:	LUN information structure that owns the block allocator.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +static int init_ba(struct llun_info *lli)
> +{
> +	int rc = 0;
> +	struct glun_info *gli = lli->parent;
> +	struct blka *blka = &gli->blka;
> +
> +	memset(blka, 0, sizeof(*blka));
> +	mutex_init(&blka->mutex);
> +
> +	/* LUN IDs are unique per port, save the index instead */
> +	blka->ba_lun.lun_id = lli->lun_index;
> +	blka->ba_lun.lsize = gli->max_lba + 1;
> +	blka->ba_lun.lba_size = gli->blk_len;
> +
> +	blka->ba_lun.au_size = MC_CHUNK_SIZE;
> +	blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE;
> +
> +	rc = ba_init(&blka->ba_lun);
> +	if (rc) {
> +		pr_err("%s: cannot init block_alloc, rc=%d\n", __func__, rc);
> +		goto init_ba_exit;

The goto here is unnecessary

> +	}
> +
> +init_ba_exit:
> +	pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli);
> +	return rc;
> +}
> +
> +/**
> + * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN
> + * @sdev:	SCSI device associated with LUN.
> + * @lba:	Logical block address to start write same.
> + * @nblks:	Number of logical blocks to write same.
> + *
> + * Return: 0 on success, -1 on failure
> + */
> +static int write_same16(struct scsi_device *sdev,
> +			u64 lba,
> +			u32 nblks)
> +{
> +	u8 scsi_cmd[MAX_COMMAND_SIZE];
> +	u8 *cmd_buf = NULL;
> +	u8 *sense_buf = NULL;
> +	int rc = 0;
> +	int result = 0;
> +	int ws_limit = SISLITE_MAX_WS_BLOCKS;
> +	u64 offset = lba;
> +	int left = nblks;
> +
> +	memset(scsi_cmd, 0, sizeof(scsi_cmd));
> +	cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL);
> +	sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
> +	if (!cmd_buf || !sense_buf) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	while (left > 0) {
> +
> +		scsi_cmd[0] = WRITE_SAME_16;
> +		put_unaligned_be64(offset, &scsi_cmd[2]);
> +		put_unaligned_be32(ws_limit < left ? ws_limit : left,
> +				   &scsi_cmd[10]);
> +
> +		left -= ws_limit;
> +		offset += ws_limit;
> +
> +		result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf,
> +				      CMD_BUFSIZE, sense_buf,
> +				      (MC_DISCOVERY_TIMEOUT*HZ), 5, 0, NULL);

5 seconds seems a little on the short side for this command. Perhaps using
sdev->request_queue->rq_timeout would be better?

> +
> +		if (result) {
> +			pr_err("%s: command failed for offset %lld"
> +			      " result=0x%x\n", __func__, offset, result);
> +			rc = -EIO;
> +			goto out;
> +		}
> +	}
> +
> +out:

You need to free cmd_buf and sense_buf here.

> +	pr_debug("%s: returning rc=%d\n", __func__, rc);
> +	return rc;
> +}
> +

> +
> +/**
> + * _cxlflash_vlun_resize() - changes the size of a virtual lun
> + * @sdev:	SCSI device associated with LUN owning virtual LUN.
> + * @ctxi:	Context owning resources.
> + * @resize:	Resize ioctl data structure.
> + *
> + * On successful return, the user is informed of the new size (in blocks)
> + * of the virtual lun in last LBA format. When the size of the virtual
> + * lun is zero, the last LBA is reflected as -1.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +int _cxlflash_vlun_resize(struct scsi_device *sdev,
> +			  struct ctx_info *ctxi,
> +			  struct dk_cxlflash_resize *resize)
> +{
> +	struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
> +	struct llun_info *lli = sdev->hostdata;
> +	struct glun_info *gli = lli->parent;
> +	struct afu *afu = cfg->afu;
> +	bool unlock_ctx = false;
> +
> +	res_hndl_t rhndl = resize->rsrc_handle;
> +	u64 new_size;
> +	u64 nsectors;
> +	u64 ctxid = DECODE_CTXID(resize->context_id),
> +	    rctxid = resize->context_id;
> +
> +	struct sisl_rht_entry *rhte;
> +
> +	int rc = 0;
> +
> +	/* req_size is always assumed to be in 4k blocks. So we have to convert
> +	 * it from 4k to chunk size
> +	 */
> +	nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len;
> +	new_size = (nsectors + MC_CHUNK_SIZE - 1) / MC_CHUNK_SIZE;

Use DIV_ROUND_UP instead.

> +
> +	pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx,"
> +		 "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle,
> +		 resize->req_size, new_size);
> +
> +	if (unlikely(gli->mode != MODE_VIRTUAL)) {
> +		pr_err("%s: LUN mode does not support resize! (%d)\n",
> +		       __func__, gli->mode);
> +		rc = -EINVAL;
> +		goto out;
> +
> +	}
> +
> +	if (!ctxi) {
> +		ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
> +		if (unlikely(!ctxi)) {
> +			pr_err("%s: Bad context! (%llu)\n", __func__, ctxid);
> +			rc = -EINVAL;
> +			goto out;
> +		}
> +
> +		unlock_ctx = true;
> +	}
> +
> +	rhte = get_rhte(ctxi, rhndl, lli);
> +	if (unlikely(!rhte)) {
> +		pr_err("%s: Bad resource handle! (%u)\n", __func__, rhndl);
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (new_size > rhte->lxt_cnt)
> +		rc = grow_lxt(afu,
> +			      sdev,
> +			      ctxid,
> +			      rhndl,
> +			      rhte,
> +			      &new_size);
> +	else if (new_size < rhte->lxt_cnt)
> +		rc = shrink_lxt(afu,
> +				sdev,
> +				ctxid,
> +				rhndl,
> +				rhte,
> +				&new_size);
> +
> +	resize->hdr.return_flags = 0;
> +	resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len);
> +	resize->last_lba /= CXLFLASH_BLOCK_SIZE;
> +	resize->last_lba--;
> +
> +out:
> +	if (unlock_ctx)
> +		mutex_unlock(&ctxi->mutex);
> +	pr_debug("%s: resized to %lld returning rc=%d\n",
> +		 __func__, resize->last_lba, rc);
> +	return rc;
> +}
> +
> +int cxlflash_vlun_resize(struct scsi_device *sdev,
> +			 struct dk_cxlflash_resize *resize)
> +{
> +	return _cxlflash_vlun_resize(sdev, NULL, resize);
> +}
> +
> +/**
> + * init_lun_table() - write an entry in the LUN table
> + * @cfg:        Internal structure associated with the host.
> + * @lli:	Per adapter LUN information structure.
> + *
> + * On successful return, a LUN table entry is created.
> + * At the top for LUNs visible on both ports.
> + * At the bottom for LUNs visible only on one port.
> + *
> + * Return: 0 on success, -errno on failure
> + */
> +static int init_lun_table(struct cxlflash_cfg *cfg, struct llun_info *lli)
> +{
> +	u32 chan;
> +	int rc = 0;
> +	struct afu *afu = cfg->afu;
> +
> +	if (lli->in_table)
> +		goto out;
> +
> +	if (lli->port_sel == BOTH_PORTS) {
> +		/*
> +		 * If this LUN is visible from both ports, we will put
> +		 * it in the top half of the LUN table.
> +		 */
> +		if ((cfg->promote_lun_index == cfg->last_lun_index[0]) ||
> +		    (cfg->promote_lun_index == cfg->last_lun_index[1])) {
> +			rc = -ENOSPC;
> +			goto out;
> +		}
> +
> +		lli->lun_index = cfg->promote_lun_index;
> +		writeq_be(lli->lun_id[0],
> +			  &afu->afu_map->global.fc_port[0]
> +			  [cfg->promote_lun_index]);

Would improve readability IMHO if you either put the second parm all on one
line or used a local variable to make it better fit on one line, rather than
line breaking where you did.

> +		writeq_be(lli->lun_id[1],
> +			  &afu->afu_map->global.fc_port[1]
> +			  [cfg->promote_lun_index]);
> +		cfg->promote_lun_index++;
> +		pr_debug("%s: Virtual LUN on slot %d  id0=%llx, id1=%llx\n",
> +			 __func__, lli->lun_index, lli->lun_id[0],
> +			 lli->lun_id[1]);

Suggest changing the pr_debug calls to dev_dbg calls where possible to scope
the messages to an adapter.

> +	} else {
> +		/*
> +		 * If this LUN is visible only from one port, we will put
> +		 * it in the bottom half of the LUN table.
> +		 */
> +		chan = PORT2CHAN(lli->port_sel);
> +		if (cfg->promote_lun_index == cfg->last_lun_index[chan]) {
> +			rc = -ENOSPC;
> +			goto out;
> +		}
> +
> +		lli->lun_index = cfg->last_lun_index[chan];
> +		writeq_be(lli->lun_id[chan],
> +			  &afu->afu_map->global.fc_port[chan]
> +			  [cfg->last_lun_index[chan]]);
> +		cfg->last_lun_index[chan]--;
> +		pr_debug("%s: Virtual LUN on slot %d  chan=%d, id=%llx\n",
> +			 __func__, lli->lun_index, chan, lli->lun_id[chan]);
> +	}
> +
> +	lli->in_table = true;
> +out:
> +	pr_debug("%s: returning rc=%d\n", __func__, rc);
> +	return rc;
> +}
> +



-- 
Brian King
Power Linux I/O
IBM Linux Technology Center


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux