1/*- 2 * Generic SCSI Target Kernel Mode Driver 3 * 4 * Copyright (c) 2002 Nate Lawson. 5 * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 14 unchanged lines hidden (view full) --- 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> |
31__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_target.c 168752 2007-04-15 08:49:19Z scottl $"); |
32 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/conf.h> 38#include <sys/malloc.h> 39#include <sys/poll.h> 40#include <sys/vnode.h> 41#include <sys/lock.h> 42#include <sys/mutex.h> 43#include <sys/devicestat.h> 44#include <sys/proc.h> 45 46#include <cam/cam.h> 47#include <cam/cam_ccb.h> 48#include <cam/cam_periph.h> 49#include <cam/cam_xpt_periph.h> |
50#include <cam/cam_sim.h> |
51#include <cam/scsi/scsi_targetio.h> 52 53/* Transaction information attached to each CCB sent by the user */ 54struct targ_cmd_descr { 55 struct cam_periph_map_info mapinfo; 56 TAILQ_ENTRY(targ_cmd_descr) tqe; 57 union ccb *user_ccb; 58 int priority; --- 97 unchanged lines hidden (view full) --- 156{ 157 targinit, "targ", 158 TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0 159}; 160PERIPHDRIVER_DECLARE(targ, targdriver); 161 162static MALLOC_DEFINE(M_TARG, "TARG", "TARG data"); 163 |
164/* 165 * Create softc and initialize it. Only one proc can open each targ device. 166 * There is no locking here because a periph doesn't get created until an 167 * ioctl is issued to do so, and that can't happen until this method returns. 168 */ |
169static int 170targopen(struct cdev *dev, int flags, int fmt, struct thread *td) 171{ 172 struct targ_softc *softc; 173 174 if (dev->si_drv1 != 0) { 175 return (EBUSY); 176 } --- 22 unchanged lines hidden (view full) --- 199 return (0); 200} 201 202/* Disable LUN if enabled and teardown softc */ 203static int 204targclose(struct cdev *dev, int flag, int fmt, struct thread *td) 205{ 206 struct targ_softc *softc; |
207 struct cam_periph *periph; |
208 int error; 209 210 softc = (struct targ_softc *)dev->si_drv1; |
211 if ((softc->periph == NULL) || 212 (softc->state & TARG_STATE_LUN_ENABLED) == 0) { 213 destroy_dev(dev); 214 FREE(softc, M_TARG); 215 return (0); 216 } 217 218 /* 219 * Acquire a hold on the periph so that it doesn't go away before 220 * we are ready at the end of the function. 221 */ 222 periph = softc->periph; 223 cam_periph_acquire(periph); 224 cam_periph_lock(periph); |
225 error = targdisable(softc); 226 if (error == CAM_REQ_CMP) { 227 dev->si_drv1 = 0; 228 if (softc->periph != NULL) { 229 cam_periph_invalidate(softc->periph); 230 softc->periph = NULL; 231 } 232 destroy_dev(dev); 233 FREE(softc, M_TARG); 234 } |
235 cam_periph_unlock(periph); 236 cam_periph_release(periph); 237 |
238 return (error); 239} 240 241/* Enable/disable LUNs, set debugging level */ 242static int 243targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 244{ 245 struct targ_softc *softc; 246 cam_status status; 247 248 softc = (struct targ_softc *)dev->si_drv1; 249 250 switch (cmd) { 251 case TARGIOCENABLE: 252 { 253 struct ioc_enable_lun *new_lun; 254 struct cam_path *path; |
255 struct cam_sim *sim; |
256 257 new_lun = (struct ioc_enable_lun *)addr; |
258 status = xpt_create_path_unlocked(&path, /*periph*/NULL, 259 new_lun->path_id, 260 new_lun->target_id, 261 new_lun->lun_id); |
262 if (status != CAM_REQ_CMP) { 263 printf("Couldn't create path, status %#x\n", status); 264 break; 265 } |
266 sim = xpt_path_sim(path); 267 mtx_lock(sim->mtx); |
268 status = targenable(softc, path, new_lun->grp6_len, 269 new_lun->grp7_len); 270 xpt_free_path(path); |
271 mtx_unlock(sim->mtx); |
272 break; 273 } 274 case TARGIOCDISABLE: |
275 if (softc->periph == NULL) { 276 status = CAM_DEV_NOT_THERE; 277 break; 278 } 279 cam_periph_lock(softc->periph); |
280 status = targdisable(softc); |
281 cam_periph_unlock(softc->periph); |
282 break; 283 case TARGIOCDEBUG: 284 { 285#ifdef CAMDEBUG 286 struct ccb_debug cdbg; 287 |
288 /* If no periph available, disallow debugging changes */ 289 if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { 290 status = CAM_DEV_NOT_THERE; 291 break; 292 } |
293 bzero(&cdbg, sizeof cdbg); 294 if (*((int *)addr) != 0) 295 cdbg.flags = CAM_DEBUG_PERIPH; 296 else 297 cdbg.flags = CAM_DEBUG_NONE; |
298 cam_periph_lock(softc->periph); |
299 xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0); 300 cdbg.ccb_h.func_code = XPT_DEBUG; 301 cdbg.ccb_h.cbfcnp = targdone; 302 |
303 xpt_action((union ccb *)&cdbg); |
304 cam_periph_unlock(softc->periph); |
305 status = cdbg.ccb_h.status & CAM_STATUS_MASK; 306#else 307 status = CAM_FUNC_NOTAVAIL; 308#endif 309 break; 310 } 311 default: 312 status = CAM_PROVIDE_FAIL; --- 11 unchanged lines hidden (view full) --- 324 int revents; 325 326 softc = (struct targ_softc *)dev->si_drv1; 327 328 /* Poll for write() is always ok. */ 329 revents = poll_events & (POLLOUT | POLLWRNORM); 330 if ((poll_events & (POLLIN | POLLRDNORM)) != 0) { 331 /* Poll for read() depends on user and abort queues. */ |
332 cam_periph_lock(softc->periph); |
333 if (!TAILQ_EMPTY(&softc->user_ccb_queue) || 334 !TAILQ_EMPTY(&softc->abort_queue)) { 335 revents |= poll_events & (POLLIN | POLLRDNORM); 336 } |
337 cam_periph_unlock(softc->periph); |
338 /* Only sleep if the user didn't poll for write. */ 339 if (revents == 0) 340 selrecord(td, &softc->read_select); 341 } 342 343 return (revents); 344} 345 --- 21 unchanged lines hidden (view full) --- 367/* Notify the user's kqueue when the user queue or abort queue gets a CCB */ 368static int 369targreadfilt(struct knote *kn, long hint) 370{ 371 struct targ_softc *softc; 372 int retval; 373 374 softc = (struct targ_softc *)kn->kn_hook; |
375 cam_periph_lock(softc->periph); |
376 retval = !TAILQ_EMPTY(&softc->user_ccb_queue) || 377 !TAILQ_EMPTY(&softc->abort_queue); |
378 cam_periph_unlock(softc->periph); |
379 return (retval); 380} 381 382/* Send the HBA the enable/disable message */ 383static cam_status 384targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) 385{ 386 struct ccb_en_lun en_ccb; --- 179 unchanged lines hidden (view full) --- 566 if (priority == -1) { 567 error = EINVAL; 568 break; 569 } 570 func_code = fuword32(&user_ccb->ccb_h.func_code); 571 switch (func_code) { 572 case XPT_ACCEPT_TARGET_IO: 573 case XPT_IMMED_NOTIFY: |
574 cam_periph_lock(softc->periph); |
575 ccb = targgetccb(softc, func_code, priority); 576 descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; 577 descr->user_ccb = user_ccb; 578 descr->func_code = func_code; 579 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 580 ("Sent ATIO/INOT (%p)\n", user_ccb)); 581 xpt_action(ccb); 582 TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, 583 &ccb->ccb_h, 584 periph_links.tqe); |
585 cam_periph_unlock(softc->periph); |
586 break; 587 default: |
588 cam_periph_lock(softc->periph); |
589 if ((func_code & XPT_FC_QUEUED) != 0) { 590 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 591 ("Sending queued ccb %#x (%p)\n", 592 func_code, user_ccb)); 593 descr = targgetdescr(softc); 594 descr->user_ccb = user_ccb; 595 descr->priority = priority; 596 descr->func_code = func_code; --- 9 unchanged lines hidden (view full) --- 606 ccb->ccb_h.targ_descr; 607 descr->user_ccb = user_ccb; 608 descr->priority = priority; 609 descr->func_code = func_code; 610 if (targusermerge(softc, descr, ccb) != EFAULT) 611 targsendccb(softc, ccb, descr); 612 targreturnccb(softc, ccb); 613 } |
614 cam_periph_unlock(softc->periph); |
615 break; 616 } 617 write_len += sizeof(user_ccb); 618 } 619 620 /* 621 * If we've successfully taken in some amount of 622 * data, return success for that data first. If --- 211 unchanged lines hidden (view full) --- 834 struct descr_queue *abort_queue; 835 struct targ_cmd_descr *user_descr; 836 struct targ_softc *softc; 837 struct ccb_queue *user_queue; 838 struct ccb_hdr *ccb_h; 839 union ccb *user_ccb; 840 int read_len, error; 841 |
842 error = 0; 843 read_len = 0; 844 softc = (struct targ_softc *)dev->si_drv1; 845 user_queue = &softc->user_ccb_queue; 846 abort_queue = &softc->abort_queue; 847 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n")); 848 849 /* If no data is available, wait or return immediately */ |
850 cam_periph_lock(softc->periph); |
851 ccb_h = TAILQ_FIRST(user_queue); 852 user_descr = TAILQ_FIRST(abort_queue); 853 while (ccb_h == NULL && user_descr == NULL) { 854 if ((ioflag & IO_NDELAY) == 0) { |
855 error = msleep(user_queue, softc->periph->sim->mtx, |
856 PRIBIO | PCATCH, "targrd", 0); 857 ccb_h = TAILQ_FIRST(user_queue); 858 user_descr = TAILQ_FIRST(abort_queue); 859 if (error != 0) { 860 if (error == ERESTART) { 861 continue; 862 } else { 863 goto read_fail; 864 } 865 } 866 } else { |
867 cam_periph_unlock(softc->periph); |
868 return (EAGAIN); 869 } 870 } 871 872 /* Data is available so fill the user's buffer */ 873 while (ccb_h != NULL) { 874 struct targ_cmd_descr *descr; 875 876 if (uio->uio_resid < sizeof(user_ccb)) 877 break; 878 TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe); 879 descr = (struct targ_cmd_descr *)ccb_h->targ_descr; 880 user_ccb = descr->user_ccb; 881 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 882 ("targread ccb %p (%p)\n", ccb_h, user_ccb)); 883 error = targreturnccb(softc, (union ccb *)ccb_h); 884 if (error != 0) 885 goto read_fail; |
886 cam_periph_unlock(softc->periph); |
887 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); |
888 cam_periph_lock(softc->periph); |
889 if (error != 0) 890 goto read_fail; 891 read_len += sizeof(user_ccb); 892 893 ccb_h = TAILQ_FIRST(user_queue); 894 } 895 896 /* Flush out any aborted descriptors */ 897 while (user_descr != NULL) { 898 if (uio->uio_resid < sizeof(user_ccb)) 899 break; 900 TAILQ_REMOVE(abort_queue, user_descr, tqe); 901 user_ccb = user_descr->user_ccb; 902 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 903 ("targread aborted descr %p (%p)\n", 904 user_descr, user_ccb)); 905 suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED); |
906 cam_periph_unlock(softc->periph); |
907 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); |
908 cam_periph_lock(softc->periph); |
909 if (error != 0) 910 goto read_fail; 911 read_len += sizeof(user_ccb); 912 913 user_descr = TAILQ_FIRST(abort_queue); 914 } 915 916 /* 917 * If we've successfully read some amount of data, don't report an 918 * error. If the error is persistent, it will be reported on the 919 * next read(). 920 */ 921 if (read_len == 0 && uio->uio_resid != 0) 922 error = ENOSPC; 923 924read_fail: |
925 cam_periph_unlock(softc->periph); |
926 return (error); 927} 928 929/* Copy completed ccb back to the user */ 930static int 931targreturnccb(struct targ_softc *softc, union ccb *ccb) 932{ 933 struct targ_cmd_descr *descr; --- 112 unchanged lines hidden (view full) --- 1046 1047/* Cancel all pending requests and CCBs awaiting work. */ 1048static void 1049abort_all_pending(struct targ_softc *softc) 1050{ 1051 struct targ_cmd_descr *descr; 1052 struct ccb_abort cab; 1053 struct ccb_hdr *ccb_h; |
1054 struct cam_sim *sim; |
1055 1056 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n")); 1057 1058 /* First abort the descriptors awaiting resources */ 1059 while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) { 1060 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 1061 ("Aborting descr from workq %p\n", descr)); 1062 TAILQ_REMOVE(&softc->work_queue, descr, tqe); --- 16 unchanged lines hidden (view full) --- 1079 xpt_print(cab.ccb_h.path, 1080 "Unable to abort CCB, status %#x\n", 1081 cab.ccb_h.status); 1082 } 1083 } 1084 1085 /* If we aborted at least one pending CCB ok, wait for it. */ 1086 if (cab.ccb_h.status == CAM_REQ_CMP) { |
1087 sim = xpt_path_sim(softc->path); 1088 msleep(&softc->pending_ccb_queue, sim->mtx, |
1089 PRIBIO | PCATCH, "tgabrt", 0); 1090 } 1091 1092 /* If we aborted anything from the work queue, wakeup user. */ 1093 if (!TAILQ_EMPTY(&softc->user_ccb_queue) 1094 || !TAILQ_EMPTY(&softc->abort_queue)) 1095 notify_user(softc); 1096} --- 91 unchanged lines hidden --- |